I am looking for a better way to do the following.
I am currently reading in up to 40 strings from a text file to build 40 variables for use in this MDFIND command (only first 2 aa_fN vars shown -- where N is a number from 1 to 40).
mdfind -onlyin "/Users/username/Documents/AAA/" "( (kMDItemUserTags == 'Gray*'cdw) && ( (kMDItemDisplayName == '*$KMVAR_aa_f1*'c) || (kMDItemDisplayName == '*$KMVAR_aa_f2*'c) ) )"
Is there a better way to do this without needing to use 40 variables?
Seems to me you'd want to approach this with a loop, something like this...
repeat with i from 1 to 40
do shell script "mdfind -onlyin \"/Users/username/Documents/AAA/\" \"( (kMDItemUserTags == 'Gray*'cdw) && ( kMDItemDisplayName == '*$KMVAR_aa_f" & i & "*'c ) )\""
-- do something with rslts
end repeat
Note: I did not test your original code for mistakes
Related
for ( i=3; i<5; i++)
do
execute some command 1
if command 2 is successful then do not run the command 1 (the for loop should continue)
if command 2 is not successful then run command 1 only once (like retry command 1 only once, after this the for loop should continue)
done
This is to note that command 2 is dependent on command 1 and command 2 can only be executed after command 1
for example:
for ( i=3; i<5; i++)
do
echo "i" >> mytext.txt ---> command 1
if "check the content of mytext.txt file to see if the value of i is actually added" ---> command 2
if it is not added then execute echo "i" >> mytext.txt (command 1) again and only once.
if i value is added to the file .. then exit and continue the loop
done
Since the "command 1" is quite big and not just an example echo statement here.I do not want to add "command 1" twice .. once outside and once inside the if condition. I want this logic in an optimized way with no redundancy of code.
Per a comment it sounds like the OP may need to invoke command 1 up to 2 times for a given $i value, but only wants to type command 1 once in the script.
Siddhartha's suggestion to use a function is probably good enough but depending on the actual command 1 (OP mentions that it's 'quite big') I'm going to play devil's advocate and assume there could be additional issues with passing some args to the function (eg, a need to escape some characters ... ??).
The general idea is to have an internal loop that can be executed at most 2 times, with logic in the loop that will allow for an 'early' exit (eg, after just one pass through the loop).
Since we're using pseudo-code I'll use the same ...
for ( i=3; i<5; i++ )
do
pass=1 # reset internal loop counter
while ( pass -le 2 )
do
echo "i" >> mytext.txt # command 1
if ( pass -eq 1 ) # after first 'command 1' execution
&& ( value of 'i' is in mytext.txt ) # command 2
then
break # break out of inner loop; alternatively ...
# pass=10 # ensure pass >= 2 to force loop to exit on this pass
fi
pass=pass+1 # on 1st pass set pass=2 => allows another pass through loop
# on 2nd pass set pass=3 => will force loop to exit
done
done
you can declare functions like
function command
{
your_command -f params
}
for ( i=3; i<5; i++)
do
if command ; then
echo "success"
else
echo "retry"
command
fi
done
I’ve got this bash script to download 52k files:
for i in {1..52000};
do wget -c "download.hebrewbooks.org/downloadhandler.ashx?req=$i" ;
done
However the server gives me an 429 error.
How can I pause the loop for X amount of time after every 5 files that are downloaded?
If i is a multiple of five, sleep.
for i in {1..52000}; do
wget -c "download.hebrewbooks.org/downloadhandler.ashx?req=$i"
((i % 5)) || sleep $X
done
Note that ((expr)) returns the Boolean value of expr, where false=0 and true=1, which is the opposite of normal Bash return codes. That's why you have to use OR || instead of AND &&. If that's too confusing, use this instead: ((i % 5 == 0)) && ...
I've two documents:
an .json
an folder with random content
where <transaction> is id+sequancial (id1, id2... idn)
I'd like to populate this structure (.json + folder) to n. I mean:
I'd like to have id1.json and id1 folder, an id2.json and id2 folder... idn.json and idn folder.
Is there anyway (shell script) to populate this content?
It would be something like:
for (i=0,i<n,i++) {
copy "id" file to "id+i" file
copy "id" folder to "id+i" folder
}
Any ideas?
Your shell syntax is off but after that, this should be trivial.
#!/bin/bash
for((i=0;i<$1;i++)); do
cp "id".json "id$i".json
cp -r "id" "id$i"
done
This expects the value of n as the sole argument to the script (which is visible inside the script in $1).
The C-style for((...)) loop is Bash only, and will not work with sh.
A proper production script would also check that it received the expected parameter in the expected format (a single positive number) but you will probably want to tackle such complications when you learn more.
Additionaly, here is a version working with sh:
#!/bin/sh
test -e id.json || { (>&2 echo "id.json not found") ; exit 1 ; }
{
seq 1 "$1" 2> /dev/null ||
(>&2 echo "usage: $0 transaction-count") && exit 1
} |
while read i
do
cp "id".json "id$i".json
cp -r "id" "id$i"
done
I'm self-answering this question because I've seen it asked all over the Internet, but with few helpful answers, and definitely no resolutions on Stack Overflow that I can find.
Example Code
Consider this code, which simply writes several lines of shell commands:
^0::
SetKeyDelay, 0, 0
myWindow = ahk_exe Notepad.exe
ControlSend, , set c=".cshrc-andrew.cheong"`n, %myWindow%
ControlSend, , set v=".vimrc-andrew.cheong"`n, %myWindow%
ControlSend, , foreach d ( /userhome/andrew.cheong /home/$USER /data/$USER )`n, %myWindow%
ControlSend, , if ( -e $d/$c ) source $d/$c`n, %myWindow%
ControlSend, , if ( -e $d/$v ) alias vim "vim -N -u $d/$v"`n, %myWindow%
ControlSend, , end`n, %myWindow%
Return
I'm writing the commands to Notepad to show that it is not an issue limited to terminal applications like PuTTy or xterm. It's easy to think so, since these applications sometimes have laggy behavior.
Example Output
Specifically when using SetKeyDelay, 0, 0 for fast "typing," I get all kinds of weird behavior, like:
Double-quotes replaced by single-quotes. Parentheses replaced by 9's and 0's. Dollar signs replaced by 4's.
set c=".cshrc-andrew.cheong'
set v=".vimrc-andrew.cheong"
foreach d ( /userhome/andrew.cheong /home/$USER /data/$USER )
if 9 -e 4d/4c 0 source 4d/4c
if ( -e $d/$v ) alias vim 'vim -n -u 4d/4v'
end
Dashes replaced by underscores. Case changes.
set c='.cshrc-andrew.cheong"
set v='.vimrc-andrew.cheong'
foreach d ( /userhome/andrew.cheong /home/4user /data/$USER )
if 9 -e 4d/$C ) source 4d/$c
if 9 _e $d/$v ) alias vim 'vim -N -u $d/$v"
end
Periods replaced by >'s. More case changes.
set c=".cshrc-andrew.cheong"
set v=">VIMrc-andrew.cheong"
foreach d ( /userhome/andrew.cheong /home/$USER /data/$USER )
if 9 -e $d/$c ) source 4d/$c
if ( -e $d/$V ) alias vim "vim -N -u $d/$v"
end
It's obvious the issue has something to do with the Shift modifier, as if it's being randomly turned on or off.
Why is this happening, and how do we fix it?
Note that there are no problems when using Send and its variants. The issue specifically arises with ControlSend, which is needed to send inputs to specific controls or to an unfocused window.
Solution
Copy this into your script (from user RHCP at AutoHotkey forums):
pSendChars(string, control := "", WinTitle := "", WinText := "", ExcludeTitle := "", ExcludeText := "")
{
for k, char in StrSplit(string)
postmessage, WM_CHAR := 0x102, Asc(char),, %Control%, %WinTitle%, %WinText%, %ExcludeTitle%, %ExcludeText%
return
}
And use it like this:
^0::
myWindow = ahk_exe Notepad.exe
line .= "set c="".cshrc-acheong""`n"
line .= "set v="".vimrc-acheong""`n"
line .= "foreach d ( /userhome/andrew.cheong /home/cama /home/$USER )`n"
line .= " if ( -e $d/$c ) source $d/$c`n"
line .= " if ( -e $d/$v ) alias vim ""vim -N -u $d/$v""`n"
line .= "end`n"
pSendChars(line, "edit1", myWindow)
Return
That's it.
Note that edit1 is Notepad's name for its text control. When using this script for PuTTy, I changed it to a blank string. Use AutoHotkey's WindowSpy program to find out the control you wish to write to.
Why
This has come up a few times before. Just to add to what Lexikos
wrote, the issue is due to the fact that controlSend uses both post
message and sendInput/sendEvent to send keystrokes. This is required
as some programs will not correctly interpret the keystrokes unless
the sent modifier keys are logically down (sent via sendInput/Event).
Modifier keys (unless explicitly stated e.g. {shitft down}) are sent
via sendInput while non-modifers are sent via postMessage. Keys sent
via postmessage are sent directly to the window and so have less delay
than the other keys/messages. Consequently it's possible for keystroke
messages to arrive out of synch resulting in unexpected characters. In
your case the capitalised letters require the shift key to be sent via
sendInput/Event.
In addition to using keyDelays, you can try controlSetText and posting
WM_Char messages. If you're working with a text control i would
recommend using controlSetText.
- RHCP on 30 Sep 2013
I am writing a csh alias so that I can use the following bash function in my csh :
function up( )
{
LIMIT=$1
P=$PWD
for ((i=1; i <= LIMIT; i++))
do
P=$P/..
done
cd $P
export MPWD=$P
}
(I stole the above bash function from here)
I have written this:
alias up 'set LIMIT=$1; set P=$PWD; set counter = LIMIT; while[counter!=0] set counter = counter-1; P=$P/.. ; end cd $P; setenv MPWD=$P'
However, I am getting the following error:
while[counter!=0]: No match.
P=/net/devstorage/home/rghosh/..: Command not found.
end: Too many arguments.
and my script is not working as intended. I have been reading up on csh from here.
I am not an expert in csh and what I have written above is my first csh script. Please let me know what I am doing wrong.
You can also do this
alias up 'cd `yes ".." | head -n\!* | tr "\n" "\/"`'
yes ".." will repeat the string .. indefinitely; head will truncate it to the number passed as argument while calling the alias ( !* expands to the arguments passed; similar to $# ) and tr will convert the newlines to /.
radical7's answer seems to be more neat; but will only work for tcsh ( exactly wat you wanted ). This should work irrespective of the shell
You can use the csh's repeat function
alias up 'cd `pwd``repeat \!^ echo -n /..`'
No loops needed (which is handy, because while constructs in tcsh seem very finicky)
For multiple lines of code, aliases must be within single quotes, and each end of line must precede a backslash. The end of the last line must precede a single quote to delimit the end of the alias:
alias up 'set counter = $1\
set p = $cwd\
while $counter != 0\
# counter = $counter - 1\
set p = $p/..\
end\
cd $p\
setenv mpwd $p'
By the way, variables set with set are better with the equal sign separated from the variable name and content; setenv doesn't require an equal sign; math functionality is provided by #; control structures make use of parentheses (though aren't required for simple tests); use $cwd to print the current working directory.