Kirodema
Kirodema

Reputation: 85

Bash for loop with multiline output from a command

I have to write a small multithreaded mysqldump script for our database and I got some problems because of a single table containing a space.

My first attempt was quite easy:

for TABLE in `mysql -u user -ppassword -e 'show tables;' dbname`  
do
    while [ 1 ]
    do
        if [ `jobs -r | wc -l` -lt $MAXTHREADS ]
        then
            break
        else
            sleep 1
        fi
    done

    mysqldump -u user -ppassword dbname $TABLE
done

Unfortunetely there was a table which contained a space. I googled a little bit for using the for loop with multiline output from commands and changing the $IFS variable was a common solution. So I changed it to \n\b (somehow $IFS was empty when I only used \n) but that was a bad idea because it caused the mysql commands to not work anymore.

I thought that this shouldn't be a problem when I get the tables beforehand and change the $IFS back everytime I use mysqldump in the for loop. But again I was mistaken as I only have one line of all tables now.
My current code:

TABLES=$(mysql -u user -ppassword -e "show tables" dbname | tail -n +2)

OIFS="$IFS"
AIFS=$(echo -en "\n\b")
IFS="$AIFS"

for TABLE in "$TABLES"
do
    IFS="$OIFS"
    while [ 1 ]
    do
        if [ `jobs -r | wc -l` -lt $MAXTHREADS ]
        then
            break
        else
            sleep 1
        fi
    done

    mysqldump -u user -ppassword dbname $TABLE
    IFS="$AIFS"

done
IFS="$OIFS"

When I try to echo the $TABLES variable I get one table per line, but the for loop is only running once with the $TABLE variable containing ALL the tables.

Thanks in advance
kiro

Upvotes: 4

Views: 6391

Answers (1)

Gordon Davisson
Gordon Davisson

Reputation: 125838

Use a while loop instead of for:

mysql -u user -ppassword -e "show tables" dbname | tail -n +2 | while read TABLE
do
    ...
done

...unless you need to set any variables inside the loop and have them available after the loop exits. Since this makes the while loop part of a pipeline, it runs in a subshell, and variables and such don't transfer to the main shell. If you need the loop to run in the main shell, you can use bash's process substitution feature instead of a standard pipe:

while read TABLE
do
    ...
done < <(mysql -u user -ppassword -e "show tables" dbname | tail -n +2)

Upvotes: 6

Related Questions