テキストファイルから端末に1行に複数のパラメータを渡す

テキストファイルから端末に1行に複数のパラメータを渡す

2つのパラメータ入力ファイルと出力ファイルを必要とするPythonプログラムがあります。入力ファイルを読み込み、出力ファイルをいくつか変更してファイルのコピーを作成します。

パラメータセットを含むテキストファイルを作成しました。複数行に複数のパラメータセットがあります。ただし、プログラムを1回実行するには1行ずつ読まなければなりません。したがって、各行には、入力ファイルと出力ファイルという2つのパラメータ(スペースで区切り)が渡されます。

パラメータを含むファイルの例(これを呼び出します。line.txtごとに複数のパラメータを持つファイル):

input-file-1-path/input-file-1-name.sql output-file-1-path/output-file-1-name.sql 
input-file-2-path/input-file-2-name.sql output-file-2-path/output-file-2-name.sql
input-file-3-path/input-file-3-name.sql output-file-3-path/output-file-3-name.sql
input-file-4-path/input-file-4-name.sql output-file-4-path/output-file-4-name.sql

私はこれを試しました:

for arg in $(< /Users/Repository/File-With-Multiple-Arguments-Per-Line.txt); 
    do python /Users/Git-Repos/MyProgram.py "$arg" "$arg" ;
done. 

使い方はこんな感じです。python MyProgram.py input-file.txt output-file.txt

やるべきことをします。何らかの理由で各引数を3回処理します(したがって、入力ファイルである最初の引数も出力ファイルと見なされます。2番目の引数と同じです)。そのため、修正してはいけない入力ファイルを修正するようになりました。入力ファイルと出力ファイルが2つの別々のgitリポジトリであるため、これを知っています。

また、1つだけ使用しましたが、"$arg"私のプログラムが必要な2番目の引数(出力ファイル)を受け取っていないことを発見しました。私が見るのは私の出力ファイルではありませんが、output: <stdout> それを使用すると"$arg" "$arg"私のプログラムが誤って解釈されます。これは同じ操作を3回実行するのと同じです。最初は予想作業を完了し、2番目は出力ファイルを出力と入力として使用しました。

以下の回避策も試しましたが、私のプログラムでは何もしません。しかし、それがする必要があるように私の端末に出力を表示しますが。エラーは発生しませんでした。

参考までに:ファイルからシェルスクリプトの複数のパラメータを読み取る

while read x y; do
    python /Users/Git-Repos/MyProgram.py "$x" "$y"
done < /Users/Repository/File-With-Multiple-Arguments-Per-Line.txt

答え1

ファイルの各行でコマンドを実行し、その行のスペースで区切られた単語を引数としてコマンドに渡しますxargs -L1

したがって、これは次のようになります。

xargs -L1 <File-With-Multiple-Arguments-Per-Line.txt python MyProgram.py

特定の形式の引用が理解されるように、xargsスペースや改行文字を含む任意のファイルパスで使用できます。ただし、引用構文はsh最新の²構文とは異なります。どちら'...'"..."二重引用符で、改行文字を含めることはできません。たとえば、次のようにできます。

tamed-input-file tamed-output-file
"Input: it's "'such a "cool" path'  'Output: Not as cool'\
'as one with'\
'newline characters'
$ xargs -L1 <a printf '1:<%s> 2:<%s>\n'
1:<tamed-input-file> 2:<tamed-output-file>
1:<Input: it's such a "cool" path> 2:<Output: Not as cool
as one with
newline characters>

xargs実装によっては、pythons stdinは読み取り専用で開かれたり(したがって)/dev/null共有されるため、stdinで読み取らないことが重要です。 GNUの実装では、次のことができます。xargsFile-With-Multiple-Arguments-Per-Line.txtpythonxargs

xargs -L1 -a File-With-Multiple-Arguments-Per-Line.txt python MyProgram.py

それを修正してください。

また、ほとんどの実装では、xargsコマンドFile-With-Multiple-Arguments-Per-Line.txtは空の場合は引数なしで一度実行されます。一部のxargs実装では、このオプションを使用してこれを回避できます-r


あなたについて:

for arg in $(< /Users/Repository/File-With-Multiple-Arguments-Per-Line.txt); 
    do python /Users/Git-Repos/MyProgram.py "$arg" "$arg" ;
done

まず、IFS分割に加えて、引用符で囲まれていないzsh部分もワイルドカードの影響を受けるため、ワイルドカードを含むファイル名に関する問題を事前に避ける必要があります。$(<...)set -o noglob

その後、ループを通過するたびに次のようになります。一つIFSで区切られ($IFSデフォルトではスペース、タブ、および改行を含む(zshではNUL))、同じ単語を2回渡しますpython。一度に2つの単語を取得するには、次の手順を実行する必要がありますzsh

for file1 file2 in $(<File-With-Multiple-Arguments-Per-Line.txt); do
  python MyProgram.py $file1 $file2
done

またはbashで:

set -o noglob
set -- $(<File-With-Multiple-Arguments-Per-Line.txt)
while (( $# > 0 )); do
  python MyProgram.py $1 $2
  shift "$(( $# < 2 ? $# : 2 ))"
done

これは、ファイルパスにスペース、タブ、または改行を含めることができないことを意味します。

同様の操作を行いxargs -L1$IFS各行にすべて別々の単語を渡すには、次の手順を実行しますzsh

while IFS= read -ru3 line; do
  python MyProgram.py $=line 3<&- # $=line for explicit IFS-splitting
done 3< File-With-Multiple-Arguments-Per-Line.txt

または:

while read -ru3 -A files; do
  python MyProgram.py $files 3<&-
done 3< File-With-Multiple-Arguments-Per-Line.txt

(置き換える必要がない限りksh93zshでも機能しますが(zshでも機能します)bashでは機能しません。)bash"${files[@]}"$files-a-A

POSIX的に:

set -o noglob
while IFS= read -r <&3 line; do
  python MyProgram.py $line 3<&- # implicit split+glob with glob disabled above
done 3< File-With-Multiple-Arguments-Per-Line.txt

それでも、任意のファイルパスは許可されません。xargs -L1dosなどの特定の形式の引用を理解する単語に行を分割するには、次のようにしますzsh

while IFS= read -ru3 line; do
  python MyProgram.py "${(Q@)${(z)line}}" 3<&- # $=line for explicit IFS-splitting
done 3< File-With-Multiple-Arguments-Per-Line.txt

ここで、zパラメータ拡張フラグは言語と同じトークン化を実行して引用符の1つのレイヤーを削除し、引用符の中に空のzshパラメータを残します(完了したように)。Q@"$@"

その後、次のものを使用できます。

"Input: it's "'such a "cool" path' $'Output: Not as cool\nas one with\nnewline characters'

¹長すぎず、一部のxargs実装では、ユーザーのロケールで有効なテキストにデコードできます。

²これはMasheyシェル(xargs1970年代後半にPWB Unixで導入されたPWBシェルとも呼ばれます)に近いです。

答え2

python各行に入力ファイル名と出力ファイル名を持つファイルの内容を繰り返して、2つのファイル名を引数として渡すスクリプトを呼び出すようです。

問題がpythonファイルを読み取ることができるスクリプトや権限、またはファイルの存在に関連していないと仮定すると、while質問の例は機能します。

しかし、ここに以下を使用する代替方法がありますwhile(これはPythonに渡された引数のみを表示しますが、まだ実行していません)。

§ cat File-With-Multiple-Arguments-Per-Line.txt | xargs -n 2 echo python 
python input-file-1-path/input-file-1-name.sql output-file-1-path/output-file-1-name.sql
python input-file-2-path/input-file-2-name.sql output-file-2-path/output-file-2-name.sql
python input-file-3-path/input-file-3-name.sql output-file-3-path/output-file-3-name.sql
python input-file-4-path/input-file-4-name.sql output-file-4-path/output-file-4-name.sql

以下のようにその出力をファイルにパイプしてから、後で実行できます。これは、パラメータが正しく渡されたことを確認するのに役立ちます。

§ cat File-With-Multiple-Arguments-Per-Line.txt | xargs -n 2 echo python > script.sh
§ chmod +x ./script.sh
§ ./script.sh

次のように実行のためにbashにパイプしてスクリプトを直接呼び出すこともできます。

§ cat File-With-Multiple-Arguments-Per-Line.txt | xargs -n 2 echo python | bash -

関連情報