Why isn't pattern matching working with 'rm' from bash script? [duplicate] - linux

Running this script, bash ./cleanup.bash,
#!/bin/bash
## Going to directory-moving stuff
rm -rf !(composer.json|.git)
Gives the error:
cleanup.bash: line 10: syntax error near unexpected token '('
cleanup.bash: line 10: 'rm -rf !(composer.json|.git)'
But if I run in in the terminal directly, there aren't any problems:
rm -rf !(composer.json|.git)
I tried stripping out all other lines, but I still get the error.
How do I enter this correctly in the Bash script?
I'm on Ubuntu, and this was all done locally, not on a remote.

I guess your problem is due to the shell extended glob option not set when run from the script. When you claim it works in the command line, you have somehow set the extglob flag which allow to !() globs.
Since the Bash script, whenever started with a #!/bin/bash, starts a new sub-shell, the extended options set in the parent shell may not be reflected in the new shell. To make it take effect, set it in the script after the shebang:
#!/bin/bash
shopt -s extglob
## Going to directory-moving stuff
rm -rf !(composer.json|.git)

Related

Escaping glob brackets in bash script [duplicate]

Running this script, bash ./cleanup.bash,
#!/bin/bash
## Going to directory-moving stuff
rm -rf !(composer.json|.git)
Gives the error:
cleanup.bash: line 10: syntax error near unexpected token '('
cleanup.bash: line 10: 'rm -rf !(composer.json|.git)'
But if I run in in the terminal directly, there aren't any problems:
rm -rf !(composer.json|.git)
I tried stripping out all other lines, but I still get the error.
How do I enter this correctly in the Bash script?
I'm on Ubuntu, and this was all done locally, not on a remote.
I guess your problem is due to the shell extended glob option not set when run from the script. When you claim it works in the command line, you have somehow set the extglob flag which allow to !() globs.
Since the Bash script, whenever started with a #!/bin/bash, starts a new sub-shell, the extended options set in the parent shell may not be reflected in the new shell. To make it take effect, set it in the script after the shebang:
#!/bin/bash
shopt -s extglob
## Going to directory-moving stuff
rm -rf !(composer.json|.git)

removing files except some in a bash script

I was trying to delete some files in a bash script and exclude some I still need afterwards. This is what I came up with:
if [ $var1 -eq 0 ]; then
echo "$var1 = 0"
shopt -s extglob
rm /home/someone/!(file1.txt|file2.png|file3.pdf|file4.csv)
else
echo "$var1 = 1"
shopt -s extglob
rm -rf /home/someone/!(file1.txt|file2.png|file3.pdf|file4.csv)
fi
It is working if I execute it manually on the shell, but in the script it does not even call the if-loop. As soon as I comment out the lines containing the "!" it works.
You cannot turn the extglob shell option from within a block or a function. E.g., this will fail:
shopt -u extglob
f() {
shopt -s extglob
echo *+(a)*
}
f
The reason is that the command shopt -s extglob is not executed when the block is parsed… and the parser will hence complain when it encounters the extended glob +(a). See the relevant section of the glob page on Greg's wiki:
extglob changes the way certain characters are parsed. It is necessary to have a newline (not just a semicolon) between shopt -s extglob and any subsequent commands to use it. You cannot enable extended globs inside a group command that uses them, because the entire block is parsed before the shopt is evaluated. Note that the typical function body is a group command. An unpleasant workaround could be to use a subshell command list as the function body.
If you really want this behavior, though, you can use eval, but that's really not recommended at all! Instead, move the shopt -s extglob out of the block. In fact, it is customary to put the shell options at the beginning of the script and use them throughout the script (when applicable). I don't think you'll run into any problems if you use extglob throughout the script.
As #choroba is hinting towards, you need to run your script either as bash my_script.sh or ./my_script.sh to run it with Bash. If you run sh my_script.sh the shell may not support extglob.
A useful way to tell what's actually happening is to add set -o xtrace to the top of the script (after the shebang line). That should tell you what actually gets executed. I'd also add set -o errexit to make sure the script stops at the first failing command, and quote the reference to $var1.

return no errors on command line syntax

If you run rm -r /var/some/dir/* and the dir is empty an error is returned
How can you supress this error so its not returned?
I use it in a linux bash script
Apart from redirecting to stderr, you can also use -f:
rm -rf /var/some/dir/*
From man rm:
-f, --force
ignore nonexistent files and arguments, never prompt
Redirect stderr:
rm -r /var/some/dir/* 2>/dev/null
Since you question mentions [if] dir is empty an error is returned (so assuming the directory exists), that's because the glob /var/some/dir/* matches nothing, hence bash (with the default unset nullglob and failglob) will pass the string /var/some/dir/* verbatim. And there are no such files, so rm complains.
Since you're using this in a bash script, I would advise you to proceed as follows:
shopt -s nullglob
shopt -u failglob
declare -a files=( /var/some/dir/* )
if (( ${#files[#]} )); then
rm -r -- "${files[#]}" # || error handling
fi
The shopt -s nullglob will make globs expand to nothing if no matching files exist,
You put the matching files in an array files (and because nullglob is set, the array files is empty if there are no matches),
If there are matching files, then rm them.
Proceeding like this will make your script more robust, as you'll be able to catch a genuine error occuring in rm (with the || error handling part) and not confuse this with an error occurring from a non-matched glob.
Doing so, you will not launch a random command with uncontrolled arguments.
Remark. It is not quite true that the error you obtain occurs only when the directory is empty. It occurs when the directory contains no files, except possibly hidden files. If you want to really purge the directory from also potential hidden files, you must shopt -s dotglob so that the glob will also match hidden files.

Bash file shows "ln: command not found"

I'm trying to create a bash script to setup my development environment. The script is running as root but I get the error line 11: ln: command not found
#!/bin/bash
#Require script to run as root - doesn't work - syntax error in conditional expression: unexpected token `;'
#if [[ $(/usr/bin/id -u) -ne 0]]; then
# echo "Script must be run as root";
# exit;
#fi
#PHPMyAdmin
PATH="/etc/apache2/sites-available/phpmyadmin.local";
if [ ! -a PATH ]; then
ln -s /home/user/Ubuntu\ One/htdocs/vhosts/phpmyadmin.local PATH;
a2ensite phpmyadmin.local;
fi
PATH=...
Congratulations, you've clobbered how the shell finds commands. Don't do that.
PATH tells the shell where to look for commands. In your case, it looks for ln somewhere in /etc and predictably doesn't find it there.
You should use a different name.

Executing shell script in ubuntu

Maybe I am missing something here but I have the following small bash script to delete some old files that get created when using flex and yacc its pretty simple but when I run the script it echos the result to the terminal but does not delete the file I'm probably missing something stupid could you guys point me in the right direction.
#!/bin/bash
echo "rm -f y.tab.h"; (just using one file for now)
I tried changing it to
echo rm -f y.tab.h;
but still no luck
I tried executing it with bash delete.sh and sh delete.sh and even using chmod +x on the file and executing it with ./
Remove echo statement
Just use
rm -f y.tab.h

Resources