oranie's blog

旧:iをgに変えると・・・なんだっけ・・・

【bashメモ】for文で「>(リダイレクト)」がエスケープされ上手く動かない時などの対応(10/22追記)

正直もっとちゃんとした対応方法がある気がしますが、とりあえず対応した。

bashでDBバックアップ用に各コマンドを実行して、途中でエラーになったらアラートメールを飛ばすスクリプトを書いていた時に
標準出力からファイル書き込みを利用したコマンドをそのまま配列に入れてfor文で回そうとするとエラーになった。
こんな感じの。

#!/bin/bash
export PATH=$PATH

LIST[0]="mysqldump -u root -phogehoge -A --opt \
--single-transaction --flush-logs --master-data=2 \
--hex-blob > ./test.dump"
LIST[1]="echo hogehoge"
LIST[2]="date"
OLDIFS=IFS
IFS=$'\n'

for CMD in ${LIST[*]} ; do
    IFS=$' \t\n'
    ${CMD}
    if [ $? -ne 0 ]; then
        exit 1
    fi
    IFS=${OLDIFS}
done

??と思い、bash -x で実行すると、「〜〜'>'〜〜エラーだよ」的な表示が出ていてどうやらエスケープされてしまっている様子。

なので、一度関数化する事でfor文でエスケープされないように回避した。

#!/bin/bash
export PATH=$PATH

dbbackup(){
    mysqldump -u root -phogehoge -A --opt \
    --single-transaction --flush-logs --master-data=2 \
    --hex-blob > ./test.dump
}

LIST[0]="dbbackup"
LIST[1]="echo hogehoge"
LIST[2]="date"
OLDIFS=IFS
IFS=$'\n'

for CMD in ${LIST[*]} ; do
    IFS=$' \t\n'
    ${CMD}
    if [ $? -ne 0 ]; then
        exit 1
    fi
    IFS=${OLDIFS}
done

あと、途中で

OLDIFS=IFS
IFS=$'\n'

とかやっているのは、各コマンドにオプションとかをつけて実行する為のスペースが、何もしない状態だと
for文で分割されてしまい、$CMD部分でコマンドとオプションがバラバラで実行される為、分割する条件を変更している。
で、最後に元に戻す様に処理を入れた。

以上、個人的なメモ。

                                                                                                                                              • -

id:mikedaさんからコメントで頂いたevalを使えばもっとスマート!という方法で
問題無く出来ました!こんな感じっす。全部のコマンドでリダイレクト入れても問題無し。
(*´∀`*)

#!/bin/bash
export PATH=$PATH

LIST[0]="mysqldump -u root -phogehoge -A --opt \
--single-transaction --flush-logs --master-data=2 \
--hex-blob > ./test.dump"
LIST[1]="echo hogehoge!!! > a.txt"
LIST[2]="date >> b.txt"

for CMD in "${LIST[@]}";do
    eval $CMD
    if [ $? -ne 0 ]; then
        echo "NG!!! >< " > shippai.txt
        exit 1
    fi
done