BASH script does not interpret logical Not in glob expression [duplicate] - bash

This question already has answers here:
Pattern match does not work in bash script
(3 answers)
Closed 1 year ago.
The following script(s) work fine if copy and pasted into the shell. However, when creating a script file and interpreting with BASH- it fails with error: "Syntax error:"(" unexpected. It appears the logical "!" (not) is not being interpreted.
'''
#!/bin/bash
for TARGETFOLDER in !(*Sidereal);
do cd $TARGETFOLDER;
echo "--->---> Processing" $TARGETFOLDER;
for FILTERFOLDER in *;
do cd $FILTERFOLDER;
echo "--->--->---> Processing" $TARGETFOLDER $FILTERFOLDER;
pp_prepare -keep_wcs *r.fits;
pp_photometry -snr 3 -minarea 12 -aprad 6 *r.fits;
pp_calibrate -instrumental *r.fits;
cd ..;
done;
cd ..;
done;
'''
Is there a way to have this interpreted correctly- or maybe rewritten to conform to an interpreter? The original script as given was not formatted nicely... sorry
thanks

You need to explicitly enable extended glob support.
shopt -s extglob
for TARGETFOLDER in !(*Sidereal);
...

Related

The `ls` command is interpreting my directory with spaces as multiple directories [duplicate]

This question already has answers here:
Why does shell ignore quoting characters in arguments passed to it through variables? [duplicate]
(3 answers)
Closed 3 years ago.
I'm trying to pass a dynamic command that executes ls as a string that lists the files of a directory that contains spaces. However, my ls command always interprets my one directory containing spaces as multiple directories no matter what I do.
Consider the following simplified version of my shell script:
#!/bin/sh
export WORK_DIR="/Users/jthoms/Dropbox (My Company)/backup-jthoms/Work"
echo "WORK_DIR=$WORK_DIR"
export LS_CMD="ls -A \"$WORK_DIR/dependencies/apache-tomcat-8.0.45/logs\""
echo "LS_CMD=$LS_CMD"
if [ -n "$($LS_CMD)" ]
then
echo "### Removing all logs"
sudo rm "$WORK_DIR/dependencies/apache-tomcat-8.0.45/logs/*"
else
echo "### Not removing all logs"
fi
This script results in the following output:
WORK_DIR=/Users/jthoms/Dropbox (My Company)/backup-jthoms/Work
LS_CMD=ls -A "/Users/jthoms/Dropbox (My Company)/backup-jthoms/Work/dependencies/apache-tomcat-8.0.45/logs"
ls: "/Users/jthoms/Dropbox: No such file or directory
ls: (My: No such file or directory
ls: Company)/backup-jthoms/Work/dependencies/apache-tomcat-8.0.45/logs": No such file or directory
### Not removing all logs
How can I correctly escape my shell variables so that the ls command interprets my directory as a single directory containing spaces instead of multiple directories?
I recently changed this script which used to work fine for directories containing no spaces but now doesn't work for this new case. I'm working on Bash on MacOSX. I have tried various forms of escaping, various Google searches and searching for similar questions here on SO but to no avail. Please help.
Variables are for data. Functions are for code.
# There's no apparent need to export this shell variable.
WORK_DIR="/Users/jthoms/Dropbox (My Company)/backup-jthoms/Work"
echo "WORK_DIR=$WORK_DIR"
ls_cmd () {
ls -A "$1"/dependencies/apache-tomcat-8.0.45/logs
}
if [ -n "$(ls_cmd "$WORK_DIR")" ]; then
then
echo "### Removing all logs"
sudo rm "$WORK_DIR/dependencies/apache-tomcat-8.0.45/logs/"*
else
echo "### Not removing all logs"
fi
However, you don't need ls for this at all (and in general, you should avoid parsing the output of ls). For example,
find "$WORK_DIR/dependencies/apache-tomcat-8.0.45/logs/" -type f -exec rm -rf {} +
You could use
# ...
if [ -n "$(eval "$LS_CMD")" ]
# ...
See http://mywiki.wooledge.org/BashFAQ/050
Or even
# ...
if [ -n "$(bash -c "$LS_CMD")" ]
# ...
But you are probably better off using a dedicated function and/or even something more specific to your problem (using find instead of ls is usually a good idea in these cases, see some examples in the answers for this question).
Use arrays, not strings, to store commands:
ls_cmd=(ls -A "$WORK_DIR/dependencies/apache-tomcat-8.0.45/logs")
echo "ls_cmd=${ls_cmd[*]}"
if [ -n "$("${ls_cmd[#]}")" ]; then …
(The syntax highlighting on the last line is incorrect and misleading: we’re not unquoting ${ls_cmd[#]}; in reality, we are using nested quotes via a subshell here.)
That way, word splitting won’t interfere with your command.
Note that you can’t export arrays. But you don’t need to, in your code.
As others have noted, it’s often a better idea to use functions here. More importantly, you shouldn’t parse the output of ls. There are always better alternatives.

Passing Path to Bash Script, Shorthand notation [duplicate]

This question already has answers here:
How to manually expand a special variable (ex: ~ tilde) in bash
(19 answers)
Tilde expansion in quotes
(3 answers)
Closed 4 years ago.
I'm not sure if this question has been asked or answered. If it has, I apologize. I wasn't too sure what to look for, but I'm writing a bash script to take in a path from the user, my script works with absolute and relative paths. But I was wondering if there was a way to interpret the shorthand notation to these paths. For example ~/ for home or . for current or ../ for a directory up. I was having a bit of trouble figuring this out. Here is my current bash script for reference.
#!/bin/bash
echo "What is the path you'd like me to search?"
read PASSED
while [ ! -d $PASSED ]; do
echo "$PASSED is not a valid directory"
echo "Please provide a valid Path"
read PASSED
done
ls -l $PASSED | awk -v user=`whoami` '{ if($3 == user){print $0}}'
. and .. are not shortcuts, they're actual directory names that exist in every directory. You don't need to do anything to support this.
~, however, is bash syntax that you can emulate.
In the simplest case, just check for a leading ~ and replace:
# Read some path
printf 'Enter a path: '
IFS='' read -r mypath
# If the path starts with ~, replace it with $HOME
[[ $mypath = '~'* ]] && mypath="$HOME${mypath#'~'}"
# Show what we got
echo "The path is $mypath, aka $(realpath "$mypath")"
Note that this does not support the various other ~ syntaxes like ~username or ~+

How to make a vim variable determinable by bash? [duplicate]

This question already has answers here:
How to check if a files exists in a specific directory in a bash script?
(3 answers)
Closed 4 years ago.
I'm not sure how to word my question exactly...
I have the code
if grep "mynamefolder" /vol/Homefs/
then
echo "yup"
else
echo "nope"
fi
which gives me the output
grep: /vol/Homefs/: Is a directory
nope
The sh file containing the code and the directory I'm targeting are not in the same directory (if that makes sense).
I want to find the words myfoldername inside /vol/Homefs/ without going through any subdirectories. Doing grep -d skip, which I hoped would "skip" subdirectories and focus only directories, just gives me nope even though the folder/file/word I'm testing it on does exist.
Edit: I forgot to mention that I would also like mynamefolder to be a variable that I can write in putty, something like
./file spaing and spaing being the replacement for myfoldername.
I'm not sure if I did good enough explaining, let me know!
You just want
if [ -e /vol/Homefs/"$1" ]; then
echo yup
else
echo nope
fi
The [ command, with the -e operator, tests if the named file entry exists.
vim is not involved, and grep is not needed.
If you're insisting on using grep, you should know grep doesn't work on directories. You can convert the directory listing to a string.
echo /vol/Homefs/* | grep mynamefolder

Bash for loop and glob expansion [duplicate]

This question already has answers here:
Looping on empty directory content in Bash [duplicate]
(2 answers)
Closed 7 years ago.
Consider the following bash code:
for f in /tmp/*.dat; do echo ${f}; done
when I run this and there is no *.dat file in /tmp the output is:
/tmp/*.dat
which is clearly not what I want. However, when there is such a file, it will print out the correct one
/tmp/foo.dat
How can I force the for loop to return 'nothing' when there is no such file in the directory. The find-command is not an option, sorry for that :/ I would like to have also a solution without testing, if *.dat is a file or not. Any solutions so far?
This should work:
shopt -s nullglob
...
From Bash Manual
nullglob
If set, Bash allows filename patterns which match no files to expand
to a null string, rather than themselves.

for loop on files that don't exist [duplicate]

This question already has answers here:
How to skip the for loop when there are no matching files?
(2 answers)
Closed 3 years ago.
I want to process a set of files (*.ui) in the current directory. The following script works as expected if some *.ui files are found. But if no .ui file exist the current directory, the for loop is entered all the same. Why is that ?
for f in *.ui
do
echo "Processing $f..."
done
It prints :
Processing *.ui...
Use:
shopt -s nullglob
From man bash:
nullglob
If set, bash allows patterns which match no files (see Pathname Expansion
above) to expand to a null string, rather than themselves.
You already have the how, the 'why' is that bash will first try to match *.ui to files, but if that doesn't work (it gets no results) it will assume you meant the string "*.ui".
for f in "*.ui"
do
echo "Processing $f..."
done
wil indeed print "Processing *.ui".

Resources