Why is my bash script not expanding wildcards inside quotes
I have some zipped cpp sources and I wrote this script to compile them all into binary:
#!/bin/bash
BASE_DIR="$HOME/cpp"
WORKING_DIR=$BASE_DIR/working
BIN_DIR=$BASE_DIR/bin
LOG_FILE=$BASE_DIR/log.txt
mkdir $BIN_DIR
mkdir $WORKING_DIR
for dirname in $BASE_DIR; do
for zip_file in "$BASE_DIR/$dirname/*.zip"; do
echo "Processing $zip_file" >> $LOG_FILE
echo -n "Unzipping ... " >> $LOG_FILE
unzip_message=$(unzip $zip_file -d $WORKING_DIR 2>&1)
if [[ $? -ne 0 ]]; then
echo "Good." >> $LOG_FILE
else
echo "Bad!" >> $LOG_FILE
echo "Error message: $unzip_message" >> $LOG_FILE
continue
fi
id=$(echo $zip_file | cut -d. -f1)
echo -n "Compiling program ... " >> $LOG_FILE
gcc_message=$(g++ "$WORKING_DIR/*.cpp" -o $id -std-c++11 2>&1)
if [[ $? -eq 0 ]]; then
mv $id $BIN_DIR/$id
chmod +x $BIN_DIR/$id
echo "Good. product is at $BIN_DIR/$id." >> $LOG_FILE
else
echo "Bad." >> $LOG_FILE
echo "g++ message: $gcc_message" >> $LOG_FILE
fi
rm $WORKING_DIR/*
done
echo "Proccessing done."
done
I am discarding expansion substitution. Magazines:
Processing /home/john/cpp//home/john/cpp/*.zip
Unzipping ... Good.
Compiling program ... Bad.
g++ message: g++: error: /home/john/cpp/working/*.cpp: No such file or directory
g++: error: unrecognized command line option ‘-std-c++11’
g++: fatal error: no input files
compilation terminated.
Can anyone point out where my problem is? Why aren't the masks expanding?
Thanks in advance.
source to share
Always move wildcard expansion *
outside of quotes in the shell. Within quotes, it is treated as a literal character. Shell pathname expansion occurs only if *
not quoted.
g++ "$WORKING_DIR/"*.cpp -o $id -std-c++11 2>&1
and once in the original for the loop
for zip_file in "$BASE_DIR/$dirname/"*.zip; do
bash
scans each word for characters*
,?
and[
. If one of these characters appears, that word is treated as a pattern and is replaced with an alphabetically sorted list of filenames matching the pattern.... If the substitution appears in double quotes , word splitting and path expansion are not performed on the results.
source to share
I see several problems here:
-
for dirname in $BASE_DIR; do
doesn't get the list of subdirectories in$BASE_DIR
, it just gets$BASE_DIR
. You wantfor dirname in "$BASE_DIR"/*/; do
. Note that it$BASE_DIR
must be in double quotes, but*
cannot or will not be expanded. Also,/
it restricts its directories at the end, so it won't try to work on files (like a log file).By the way, you probably want to add a couple of checks here because it will try to work in every subdirectory under
$BASE_DIR
, including$BIN_DIR
and$WORKING_DIR
. -
for zip_file in "$BASE_DIR/$dirname/*.zip"; do
should befor zip_file in "$dirname"*.zip"; do
- the variable$dirname
will contain$BASE_DIR
, so you shouldn't add it again (note the references to "/ home / john / cpp // home / john / cpp /" in your output) and again*
should be outside the quotes or it shouldn't will expand. Also, if you use the formula above for$dirname
, it will already end with a "/", so you don't need to add another. -
gcc_message=$(g++ "$WORKING_DIR/*.cpp" -o $id -std-c++11 2>&1)
- move*
outside the quotes again . Variable references should usually be wrapped in double quotes, but shell patterns cannot be specified or will not work.
There are also a number of other variable references that need to have double quotes (like every reference to $LOG_FILE
). You must run the script through shellcheck.net ; it is really good to point out such things. Finally, I recommend not using all-caps variable names, as there are many variables for all caps that have special meanings, and if you use one of them by mistake, it can cause problems.
source to share