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.

0


source to share


3 answers


This is because whildcards are not interpreted with double quotes. Move the whildcard outside the quoted string:



for zip_file in "$BASE_DIR/$dirname/"*.zip; do
                                    ^
                                    |
          Mode the quote here----+--'
                                 |
                                 v
gcc_message=$(g++  "$WORKING_DIR/"*.cpp -o $id -std-c++11 2>&1)

      

+1


source


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

      

From the man pagebash(1)

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.

+1


source


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 want for 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 be for 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.

+1


source







All Articles