Problem using cp command with negation (!) on crontab - bash

#!/bin/bash
cd /var/www/html/tpd
cp -pr !(edc|dti|swb|audio|blog|buy|dpt|dpt.git|dpt-staging-server|dti_old|images|images2|images_linkshare|smarty-3.1.30|swb.com|swb.com.temp|talent|template_c|video|yout|yout-admin|All_About_Your_Canine_Friend.pdf|Canine_Cuisine.pdf|definitiveguide.pdf|GroomingYourDogAtHome-FreeReport.pdf|HowToStopYourPuppyOrOlderDogFromBiting.pdf|Network Merchants API.pdf|SuperDogsandPuppies.pdf|TopDogs.pdf|UltimateBreedGuide.pdf|10CommonProblemsofAdultDogs.pdf|10CommonProblemsofPuppies.pdf|45commonlyaskedquestionsondoggrooming.pdf|g.tar.gz|h.tar.gz|dti_back.tar.gz|Canine_Cuisine.zip|deluxe_version.zip|h.zip|StyleXPInstallMale.zip|UltimateBreedGuide.zip|videotranscripts.zip|101ways.zip) weeklyBackup
tar -cvf weeklyBackup.tar.gz weeklyBackup
rm -rf weeklyBackup
I am taking a weekly backup for only some selected files and this is the script that I am using. It works perfectly when running manually but when I am entering this is a crontab, it returns an error line 3: syntax error near unexpected token `('

The syntax !(name1|name2|name3) is what's called an "extglob". This is an optional extension to bash, not enabled by default.
To enable this syntax, you need to run (as a prior line in your script):
shopt -s extglob
Presumably your dotfiles are already doing this for interactive shells, which is why the syntax works for you out-of-the-box. (Also ensure that if your script is invoked from cron with sh scriptname, bash scriptname is used instead, or the code is modified to honor the shebang).

Related

command substitution not working in alias?

I wanted to make an alias for launching a vim session with all the c/header/makefiles, etc loaded into the buffer.
shopt -s extglob
alias vimc="files=$(ls -A *.?(c|h|mk|[1-9]) .gitconfig [mM]akefile 2>/dev/null); [[ -z $files ]] || vim $files"
When I run the command enclosed within the quotations from the shell, it works but when run as the alias itself, it does not. Running vimc, causes vim to launch only in the first matched file(which happens to be the Makefile) and the other files(names) are executed as commands for some reason(of course unsuccessfully). I tried fiddling around and it seems that the command substitution introduces the problem. Because running only the ls produces expected output.
I cannot use xargs with vim because it breaks the terminal display.
Can anyone explain what might be causing this ?
Here is some output:
$ ls
Makefile readme main.1 main.c header.h config.mk
$ vimc
main.1: command not found
main.c: command not found
.gitignore: command not found
header.h: command not found
config.mk: command not found
On an related note, would it be possible to do what I intend to do above in a "single line", i.e without storing it into a variable files and checking to see if it is empty, using only the output stream from ls?

scp command fails with syntax error when used in a bin/sh script

The following command works perfectly when called directly from the terminal
scp -r ./!(node_modules|public) $SERVER:$WEBSITE_SRC
but when the same command is added to a shell script it fails with the following error
line 9: syntax error near unexpected token `('
here is the script for reference:
#!/bin/sh
set -e
SERVER=127.0.0.1
WEBSITE_SRC=~/website/src
echo "Deploying changes to the website src code"
scp ./.env* $SERVER:$WEBSITE_SRC
scp -r ./!(node_modules|public) $SERVER:$WEBSITE_SRC
!(node_modules|public) is extended globbing syntax. You should do two things.
Change the shebang line to #!/bin/bash to make sure your script is run by bash.
Put shopt -s extglob near the top to enable extended globbing syntax.
If it works interactively, it's probably because you have shopt -s extglob in one of your shell initialization files (e.g. ~/.bashrc).

Shell globbing negation doesn't work in bash

I'm currently confused why shell globbing in terminal works with negation but shows an error when running in bash.
Take the commands executed in the terminal below, which shows all js files within the ./HTML directory except for js files that ends with .bundle.js.
$ shopt -s globstar
$ ls ./HTML/**/!(*.bundle).js
The command above works perfectly, now let's put it in a bash file
list-js.sh
#!/usr/bin/env bash
shopt -s globstar
ls ./HTML/**/!(*.bundle).js
Executing it in a terminal:
$ bash list-js.sh
list-js.sh: line 4: syntax error near unexpected token `('
list-js.sh: line 4: `ls ./HTML/**/!(*.bundle).js'
As you can see, it shows a syntax error.
globstar only enables the ** pattern. The extglob option allows !(...). Somewhere in your interactive shell, that has already been enabled (perhaps in your .bashrc, perhaps you typed shopt -s extglob earlier). However, it needs to be enabled explicitly in your script, since such settings are not inherited from the shell that starts the script.
#!/usr/bin/env bash
shopt -s globstar extglob
ls ./HTML/**/!(*.bundle).js
(As an aside, ** without globstar does not cause a syntax error because it is treated simply as two adjacent *s, the second one being redundant.)

Why does pattern "*.so?(.*)" produce a syntax error in a script but not on command line?

The pattern is a little unusual because I added the trailing "?(.*)" portion. It works on command line as I expected but I get a syntax error for the same in a script.
$ bash --version
GNU bash, version 4.3.11(1)-release (i686-pc-linux-gnu)
...
$ cat x.sh
touch a.so a.so.1
ls *.so?(.*)
rm *.so?(.*)
$ touch a.so a.so.1
$ ls *.so?(.*)
a.so a.so.1
$ rm *.so?(.*)
$ ls
x.sh
$ bash x.sh
x.sh: line 2: syntax error near unexpected token `('
x.sh: line 2: `ls *.so?(.*)'
$
You are using an extended glob but these aren't enabled by default within a script. In order to using them, they must be explicitly enabled. You can do so by adding this before the line:
shopt -s extglob
To disable them later on in the script, you can use shopt -u extglob.
As chepner rightly points out, this feature isn't enabled by default in the interactive shell, either. Presumably, this line is present either in one of your system-wide startup scripts or one of your personal ones.

Regular expression on a remote script

I'm trying to run a script on a remote machine (both machines use bash), using ssh, which has the following lines:
cd /home/invitado/
rm -r !(Desktop|Downloads|Videos|Pictures)
So when I run ssh hostname './remove', I get this error:
syntax error near unexpected token `('
I tried appending this line to the script
shopt -s extglob
But I'm still having the same error, so what should I do? Thanks for your help.
shopt -s extglob should be before rm -r !(Desktop|Downloads|Videos|Pictures).
To verify, see what is the original value of extglob by running just shopt.
Note: In my case, that value was set when I run the command rm directly from the shell. But when I put it in script, it failed. Realized that extglob is set by default when running from interactive shell. & It is disabled by default when running inside the script.

Resources