For me bash script is always some kind of tricky. I have
web_dir=/tng4/users/ldiao/AQF/wrf-chem-result/
rm "$web_dir""three_days_ago/*.gif"
the error message is
rm: cannot remove '/tng4/users/ldiao/AQF/wrf-chem-result/three_days_ago/*.gif':
No such file or directory
But if I change to
rm "$web_dir"three_days_ago/*.gif""
then it works. There is no spell errors. Can someone explains for me the reason? thanks!
The reason is that bash globbing does not work inside " "
Correct variant would be
rm -- "$web_dir/three_days_ago/"*.gif
Also, use -i option when playing with rm. This way if you make a mistake or a typo it wont delete all of your files unless you confirm that.
Related
I have read other similar questions on the forum and I can't understand why the command I tried doesn't work.
I have a list of files named in the form aaaa_100_aaaa.csv, aaaa_100_aaab.csv, aaaa_100_aaac.csv and so on, and I want to replace "100" with "200".
I'm running bash in Windows PowerShell WSL. I tried with this command
rename 's/420/410/g' *.csv
I found the same expression in many answers on the forum but it doesn't work. I got the error message
mv: target 'aaaa_100_aaaa.csv' is not a directory.
Given that the error message starts with mv:, and therefore apparently is produced by the mv ("move") command, I'm willing to bet that your bash has been configured to treat rename as an alternative name for mv. So you aren't really running the rename command at all.
To check this, run type rename. It will probably tell you that rename is an alias or a shell function, not the reference to the /usr/bin/rename executable that you expected.
You can get around this by using the full pathname to invoke rename:
/usr/bin/rename 's/100/200/g' *.csv
or by writing a backslash in front of rename to tell bash to skip any special handling of the command name:
\rename 's/100/200/g' *.csv
Of course if you're going to want to use the real rename often then remembering to do that every time will be annoying. You could unalias rename but that only fixes it in the current shell.
The long-term solution is to prevent bash from treating rename as a shortcut. To do that you'll first have to find out where the alias or function is being defined, and then remove that definition. It's probably in your $HOME/.bashrc or $HOME/.bash_profile file. If it's not there then something like grep rename $HOME/.* should find it. If that doesn't find it then it might be in a system startup file that you can't (or don't want to) edit, and in that case you could get rid of it by adding unalias rename to your .bashrc or .bash_profile.
I would like to rename my file from myscript.js to .myscript.js. How can I do it with bash? I've tried different options like mv myscript.js \.*, but it doesn't work. I've tried to experiment by adding non-dot symbol like - mv myscript.js m*, but now I don't even know where my file is (of course, I have a copy ;).
You're trying too hard.
mv myscript.js .myscript.js
Brace expansion
mv {,.}myscript.js
You can use rename utility to rename all *.js file by placing a dot before them:
rename 's/(.+\.js)/.$1/' *.js
Or in pure BASH use this for loop:
for i in *.js; do mv "$i" ".$i"; done
Don't use patterns as the target of mv (or cp for that matter). The command won't do what you want or expect, most of the time: Bash will expand the pattern at the moment when you run the command, using the file names as they were before your command was executed. So .* matches nothing (since the file doesn't exist, yet) and m* will match any file or folder which starts with m. Since you didn't get an error, chances are that the last match was a folder.
There is no way to access the previous parameter of the current command. If you want to avoid typing too much, then use Tab for both file names (so you end up with mv myscript.js myscript.js) and then use Ctrl+Left and Ctrl+Right to move quickly to the start of the second argument to insert the missing ..
You can access the parameters of the previous command, though. But that's not a feature of BASH - it's a feature of readline.
I'm writing a script that needs to erase everything from a directory except two directories, mysql and temp.
I asked a question earlier and got this code that works in the command line:
rm -rf !(mysql|temp)
However it doesn't work in the script. I get this error "Syntax error: "(" unexpected".
Is there something special about parentheses I need to do?
You probably need to explicitly enable extended patterns in your script:
shopt -s extglob
I have been trying to put the following into a bash script:
scp /cygdrive/c/Program\ Files\ \(x86\)/Spiceworks/data/configurations/LA_$(date +%F)-firewall-5520 "sf-mlawler#10.21.1.212:/home/sf-mlawler/SBOX_Automation/SBOX_Dumps/08\ -\ Security/Firewalls"
...which works as expected via command line.
When I try to place it in a script, I'm obviously going to have to double escape the spaces, anything else? I'm unable to have success with the multitude of variations I've tried.
I would think:
scp /cygdrive/c/Program\\ Files\\ \(x86\)/Spiceworks/data/configurations/LA_\$(date\ +%F)-firewall-5520 "sf-mlawler#10.21.1.212:/home/sf-mlawler/SBOX_Automation/SBOX_Dumps/08\\ \\-\\ Security/Firewalls"
...would work, but it doesn't. Any suggestions, before I go grey and bald? Thanks
I wont waste the space with all variations I've tried, but I will say I have tried escaping almost everything and basically nothing and many in between with no success. When I receive a "No such file or Directory" I obviously escape until the file actually resolves, but even when I do not get a path error, the command is not successfully completing.
I do understand this is quite a specific case, but I imagine it will help others in the future: escaping spaces, in a bash script, using embedded expect (I have tested with a #!/bin/bash shebang and the embedded expect using expect -c ' .... ' as well as #!/usr/bin/expect using a simple spawn scp command with no change.
EDIT (Based on responses):
I should have mentioned I have tried quoting it...
Quoting the first (host) part gives me the error
can't read "(date +%F)": no such variable
while executing
"spawn scp "/cygdrive/c/Program Files (x86)/Spiceworks/data/configurations/LA_$(date +%F)-firewall-5520" "sf-mlawler#10.21.1.212:/home/sf-mlawler/SBOX_..."
...it is not a variable, it is a function giving me the current date in the format year-month-day
Quoting the destination section without escaping anything gives me the error
scp: ambiguous target
The same command that worked on your bash shell should work the same in your bash script. You shouldn't and cannot escape it twice.
If it doesn't work, make sure you're testing the script from the same terminal, ensure that the script contents and your command is identical, then paste the output from your terminal when you do:
$ scp /cygdrive/c/Program\ Files\ \(x86\)/Spiceworks/data/configurations/LA_$(date +%F)-firewall-5520 "sf-mlawler#10.21.1.212:/home/sf-mlawler/SBOX_Automation/SBOX_Dumps/08\ -\ Security/Firewalls"
(successful scp output here)
$ cat testscript
(testscript contents here, should be identical to above scp command)
$ bash testscript
(unsuccessful script/scp output here)
Just stick it in quotes and stop hitting yourself, as #that_other_guy said, you cannot, and shouldn't try and escape twice, wherever you got that idea, disregard it as a source of information. (my guess is it came from "thin air")
scp "/cygdrive/c/Program Files (x86)/Spiceworks/data/configurations/LA_$(date +%F)-firewall-5520" "sf-mlawler#10.21.1.212:/home/sf-mlawler/SBOX_Automation/SBOX_Dumps/08 - Security/Firewalls"
You could even give yourself some helpers:
export PROGFILESx86="/cygdrive/c/Program Files (x86)"
export SPICEWORKS_CONFIGS="${PROGFILESx86}/Spiceworks/data/configurations"
(add them to .bashrc, exec it.) and then do:
scp "${SPICEWORKS_CONFIGS}/LA_$(date +%F)-firewall-5520" "sf-mlawler#10.21.1.212:/home/sf-mlawler/SBOX_Automation/SBOX_Dumps/08 - Security/Firewalls"
I'd also be concerned the the files you are attempting to scp actually exist, wrap it up in a condition to verify they're there, it only makes sense when you're auto-generating a filename.
firewall_config="${SPICEWORKS_CONFIGS}/LA_$(date +%F)-firewall-5520"
if [ -e "${firewall_config}" ]
then
scp "${firewall_config}" "sf-mlawler#10.21.1.212:/home/sf-mlawler/SBOX_Automation/SBOX_Dumps/08 - Security/Firewalls"
else
echo "File doesn't exist: ${firewall_config}"
fi
Update:
Since you've updated your question, it's obviously the date call that's giving you the biggest problem, again, indirection saves you doing bizarre escape-char-yoga, just get the result into a var and use that.
fw_date=$(date +%F)
firewall_config="${SPICEWORKS_CONFIGS}/LA_${fw_date}-firewall-5520"
Been searching for hours and still cant figure this out :(
Anyway, im creating a script that will automatically rsync about 40 different directories to 40 other directories on another server. if you want to see the entire script you can view it here: http://pastebin.com/Nt3KKvx9
But the important bit is the for loop where i run rsync
for ((i=0; i<${#websys[#]}; i++))
do
localpath="/nusdata/staff/NUS/NUS/Systems/${kiskasys[$i]}"
remotepath="/home/www/html/nusalaska.com/html/systems/${websys[$i]}"
rsync -rlptnvz -s "$localpath" -e "ssh -p 50014" "nusak#webserver:$remotepath/"
done
The problem is that the array "kiskasys" has many directory names that have spaces in them (Example: '101 greenbrook').
I have tried making the array variables have single quotes around them, double quotes around them, escaped spaces like '\ ', and combinations of all three. I have also tried putting the $localpath in quotes, not in quotes, etc. etc.
I guess im just confused on how the -s (--protect-args) deals with the spaces and how I can get it to work in my situation.
The error output always looks something like the following:
rsync: change_dir "/nusdata/staff/NUS/NUS/101" failed: No such file or directory (2)
or
rsync: change_dir "/nusdata/staff/NUS/NUS/'101 greenbrook'" failed: No such file or directory (2)
Any help is appreciated!
Thanks
Found My Problem
In copying my code from my script to this page I accidently copied it wrong... however in copying it wrong, what i posted above was perfectly good code that works fine haha.
so what i posted above was the solution to my own problem.
The original had single quotes in the localpath variable like so:
localpath="'/nusdata/staff/NUS/NUS/Systems/${kiskasys[$i]}'"
and the single quotes was the problem. And for everyone's benefit here is an example output
echo ${kiskasys[1]}
#output would look like this:
101 greenbrook
Basically there are no special escape characters etc.
For what it's worth, I'm not able to replicate your problem. If I set localpath and remotepath to a directory with spaces:
localpath="/home/lars/tmp/so/dir1/a directory"
remotepath="/home/lars/tmp/so/dir2/a directory"
And then run your rsync command (modified slightly for my environment):
rsync -rlptvz -s "$localpath/" -e "ssh" "localhost:$remotepath/"
It Just Works. Here's the content of dir1:
dir1/a directory/file1
dir1/a directory/file3
dir1/a directory/file2
And after running rsync, dir2 looks like this:
dir2/a directory/file1
dir2/a directory/file3
dir2/a directory/file2
Can you show a specific command line that results in the errors you're seeing above? Maybe run the script with the -x flag and show exactly how localpath and remotepath are set.