
テーブル エントリを検証する bash スクリプトがあります。最終出力値は $out で、SQL INSERT ステートメントに挿入され、/tmp/crew.txt に追加されます。$out は明らかにコンマで区切られていますが、/tmp/crew.txt 内の結果の INSERT ステートメント内の値の間にはコンマがありません。なぜこのような状況になるのでしょうか。また、/tmp/crew.txt にコンマで区切られた値が含まれるようにするには、どうすれば修正できるでしょうか。
#!/bin/bash
out=290,'02:20:00','02:40:00',20.5,NULL
echo "${out:1}"
290,'02:20:00','02:40:00',20.5,NULL
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ("${out:1}");" >> /tmp/crew.txt
vi /tmp/crew.txt
INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ( 290 '02:20:00' '02:40:00' 20 NULL);
したがって、/tmp/crew.txt の結果は次のようになります。
INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ( 290,'02:20:00','02:40:00',20,NULL);
答え1
仮説:IFS
変数には が含まれています,
。スクリプトは を変更しないIFS
ため、デフォルト以外の値は 環境にあったはずです。
この他の答え${out:1}
次のような行で引用符が解除されていることに気づきました:
echo "foo"${out:1}"bar"
引用符で囲まれていない変数単語分割とファイル名生成が行われる. 単語の分割は によって行われますIFS
。引用符で囲まれていない は${out:1}
複数の単語に分割され、echo
複数の引数を取得して、それらを単一のスペースで区切って出力します ( にecho
関係なく、これが実行されるためですIFS
)。
使用した場合printf
アドバイス通り変数が引用符で囲まれているかどうかは、次のようにするとわかりやすくなります。
printf 'INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (%s);\n' "${out:1}"
また、変数を二重引用符で囲まなかった場合、printf
複数の引数が取得され${out:1}
、複数の行が生成されます。その場合、分割が発生することは明らかです。引数echo
を連結する を使用すると、この事実はある程度わかりにくくなります。
個別の問題:
望ましい出力は、先頭にスペースを付けたくないことを示してい
"${out:1}"
ます" $out"
。変数にシングルクォートを含めるには、シェルがそれを削除しないようにする必要があります。それらをエスケープします(すでに述べた答え) または二重引用符で囲みます:
out="290,'02:20:00','02:40:00',20.5,NULL"
答え2
なぜこのようなことが起こるのか、どうすれば解決できるのか
スクリプトからエコーされた出力と空白行を削除すると、次のクリーンアップされたスクリプトが生成されます。
#!/bin/bash
out=290,'02:20:00','02:40:00',20.5,NULL
echo "${out:1}"
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ("${out:1}");" >> /tmp/crew.txt
しかしそのスクリプトを実行するとShellCheck – シェルスクリプト解析ツール次のエラーが発生します。
$ shellcheck myscript
Line 4:
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ("${out:1}");" >> /tmp/crew.txt
>> ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
$
提案どおり引用符を削除するとエラーは修正され、次のようになります。
#!/bin/bash
out=290,'02:20:00','02:40:00',20.5,NULL
echo "${out:1}"
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (${out:1});" >> /tmp/crew.txt
ただし、これを実行しても正しい答えは得られません。echo "${out:1}"
単一引用符'
が に格納されていないことが示されout
、エスケープする必要があることがわかります。
$ test.sh
90,02:20:00,02:40:00,20.5,NULL
$
これを修正すると次のようになります:
#!/bin/bash
out=290,\'02:20:00\',\'02:40:00\',20.5,NULL
echo "${out:1}"
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (${out:1});" >> test.txt
出力ファイル名を次のように変更しました。test.txt
テスト:
$ test.sh
90,'02:20:00','02:40:00',20.5,NULL
$ cat test.txt
INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (90,'02:20:00','02:40:00',20.5,NULL);
$
したがって、スクリプトの最終的な修正バージョンは次のようになります。
#!/bin/bash
out=290,\'02:20:00\',\'02:40:00\',20.5,NULL
echo "${out:1}"
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (${out:1});" >> >> /tmp/crew.txt
壊れたスクリプトのデバッグに関するレッスンはこれで終わりです。
答え3
私の場合、有効な解決策は、次の INSERT ステートメントをエコーすることです。
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (${out:1});" >> /tmp/crew.txt
逃げる必要はありません。ただし、その理由はよく分かりません。