スペースを含む文字列補間を使用してbashスクリプトからコマンドを手続き的に生成するにはどうすればよいですか?

スペースを含む文字列補間を使用してbashスクリプトからコマンドを手続き的に生成するにはどうすればよいですか?

次の月リストを使用する簡単なスクリプトを作成しようとしています。

(1月2月)

このコマンドを生成して実行するには、次のようにします。

python ExpenseManager.py -p入力/2019年1月\ Debit.CSV入力/2019年1月\ Credit.CSV -p入力/2019年2月\ Debit.CSV入力/2019年2月\ Credit.CSV

そのために私が書いたプログラムは次のとおりです。

#!/usr/bin/env bash
clear
months=(Jan Feb)
args=()
for month in ${months[@]}; do
  args=(${args[@]} -p "Inputs/${month}\\ 2019\\ Debit.CSV" "Inputs/${month}\\ 2019\\ Credit.CSV")
done
python ExpenseManager.py "${args[@]}"
exit 0

理論的にはこれはうまくいきます。結果のコマンドをエコーすると、希望の正確なコマンドが得られます。

python ExpenseManager.py -p入力/2019年1月\ Debit.CSV入力/2019年1月\ Credit.CSV -p入力/2019年2月\ Debit.CSV入力/2019年2月\ Credit.CSV

これで、プログラムで生成されたコマンドをコピー/貼り付けて実行すると正常に動作します。ただし、Bashにコマンドの実行を要求すると、Bashにエスケープされたバックスラッシュを含めるために使用されるバックスラッシュが含まれます。

Namespace(filepairs=[['Input/January\', '2019\', 'Debit.CSV', 'Input/January\', '2019\', 'Credit.CSV'], ['Input /February\2019 \Debit.CSV', '2019 年 2 月入力\Credit.CSV']]

私はそれを動作させるためにいくつかの解決策を試しました。

  • パラメータを単一の文字列にしてその上に構築してみました。

  • 次のようにパラメータを一重引用符で囲み、スペースの周囲に二重引用符を使用してみました。

args=(${args[@]} -p '入力/${月}" "2019" "Debit.CSV "入力/${月}" "2019" "Credit.CSV")

  • 次のように、スペースを必要とする引数の各部分を区切るために引用符を使用してみました。
  args=(${args[@]} -p "Inputs/${month}" "2019" "Debit.CSV" "Inputs/${month}\ 2019\ Credit.CSV")

ここと他の場所で別の解決策を見てみましたが、何も機能しないようです。したがって、この問題に固執するのではなく、誰かがBashにプログラム的に構築された補間コマンドを実行させるマジックを教えてくれることを願っています。

ベストアンサー1

echoどのコマンドが実行されているかを確認するために使用しないでください。コマンドを印刷します後ろに解析済み、つまり引用符を適用してエスケープした後削除してecho)したがって、元のコマンドライン(たとえば、構文解析前)で見られるように、出力に引用符および/またはエスケープが含まれている場合、これは重大なエラーを示します。次の2つのコマンドの出力を比較しますecho

$ month=Jan
$ var="Inputs/${month}\\ 2019\\ Debit.CSV"
$ echo $var
Inputs/Jan\ 2019\ Debit.CSV
$ echo Inputs/Jan\ 2019\ Debit.CSV
Inputs/Jan 2019 Debit.CSV

まず、エスケープ文字を印刷して次を示します。いいえ解析、適用、削除します。 2番目の例では、消えて次のようになります。はい解析、適用、削除します。

では、どうすれば解決できますか? 2つの規則:1)変数に引用符やエスケープを追加しないでください(文字列が追加の解析レベルを超える奇妙な場合を除く)。 2)代わりに、すべての変数参照の周りに二重引用符を追加します(含む${args[@]})。いくつかの奇妙な例外)。またはを使用して配列に追加できますarray+=("new" "elements")

固定スクリプトは次のとおりです。

#!/usr/bin/env bash
clear
months=(Jan Feb)
args=()
for month in "${months[@]}"; do
  args+=(-p "Inputs/${month} 2019 Debit.CSV" "Inputs/${month} 2019 Credit.CSV")
done
python ExpenseManager.py "${args[@]}"
exit 0

おすすめ記事