カンマ区切りの値を持つ Bash スクリプト変数は、別のファイルに追加されるとカンマ区切りになりません。

カンマ区切りの値を持つ Bash スクリプト変数は、別のファイルに追加されるとカンマ区切りになりません。

テーブル エントリを検証する 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

逃げる必要はありません。ただし、その理由はよく分かりません。

関連情報