テキストファイルの各行をコマンドの引数として渡す方法は?


42

.txt引数としてファイル名を受け取り、ファイルを1行ずつ読み取り、各行をコマンドに渡すスクリプトを作成しようとしています。例えば、それが実行されますcommand --option "LINE 1"、その後、command --option "LINE 2"コマンドの出力を別のファイルに書き込まれるなど、。それをどうやってやるの?どこから始めればいいのかわかりません。

回答:


26

while readループを使用する:

: > another_file  ## Truncate file.

while IFS= read -r LINE; do
    command --option "$LINE" >> another_file
done < file

別の方法は、ブロックごとに出力をリダイレクトすることです:

while IFS= read -r LINE; do
    command --option "$LINE"
done < file > another_file

最後はファイルを開くことです:

exec 4> another_file

while IFS= read -r LINE; do
    command --option "$LINE" >&4
    echo xyz  ## Another optional command that sends output to stdout.
done < file

コマンドの1つが入力を読み取る場合、コマンドがそれを食べないように、別のfdを入力に使用することをお勧めします(ここではkshzshまたはbashfor -u 3<&3代わりに移植可能に使用します)。

while IFS= read -ru 3 LINE; do
    ...
done 3< file

最後に、引数を受け入れるために、次のことができます。

#!/bin/bash

FILE=$1
ANOTHER_FILE=$2

exec 4> "$ANOTHER_FILE"

while IFS= read -ru 3 LINE; do
    command --option "$LINE" >&4
done 3< "$FILE"

実行できるもの:

bash script.sh file another_file

余分なアイデア。でbash、使用readarray

readarray -t LINES < "$FILE"

for LINE in "${LINES[@]}"; do
    ...
done

注:IFS=行の値の先頭と末尾のスペースを削除しても構わない場合は、省略できます。


28

別のオプションはxargsです。

GNUの場合xargs

< file xargs -I{} -d'\n' command --option {} other args

{} テキスト行のプレースホルダーです。

その他にxargsはがありませんが-d、一部は-0NUL区切りの入力用です。これらを使用すると、次のことができます。

< file tr '\n' '\0' | xargs -0 -I{} command --option {} other args

Unix準拠のシステム(-IPOSIXではオプションで、Unix準拠のシステムでのみ必要)では、入力を前処理して、次の形式で行を引用する必要がありますxargs

< file sed 's/"/"\\""/g;s/.*/"&"/' |
  xargs -E '' -I{} command --option {} other args

ただし、一部のxargs実装では、引数の最大サイズに非常に低い制限があることに注意してください(たとえば、Solarisでは255、Unix仕様で許可されている最小)。


に還元可能<file xargs -L 1 -I{} command --option {} other args
iruvar 14

@iruvar、いいえ、それは引用符を処理し、いくつかの空白を削除します。
ステファンシャゼラス16

7

質問を正確に保つ:

#!/bin/bash

# xargs -n param sets how many lines from the input to send to the command

# Call command once per line
[[ -f $1 ]] && cat $1 | xargs -n1 command --option

# Call command with 2 lines as args, such as an openvpn password file
# [[ -f $1 ]] && cat $1 | xargs -n2 command --option

# Call command with all lines as args
# [[ -f $1 ]] && cat $1 | xargs command --option

1
魅力のように働いた:-)
BugHunter

3

私が見つけた最良の答えは:

for i in `cat`; do "$cmd" "$i"; done < $file

編集:

... 4年後 ...

いくつかのダウン投票といくつかの経験の後、私は今、以下をお勧めします

xargs -l COMMAND < file

3
これにより、ファイル内の単語ごとにコマンドが1回呼び出されます。また、do "$cmd" "$i";理由がない限り、シェル変数への参照を常に引用する必要があります(のように)。ファイルに*単語としてaが含まれている場合、コードが実行され$cmd *、もちろん、現在のディレクトリ内のファイルのリストを使用してコマンドが実行されます。
G-Manは「Reinstate Monica」と言う

1
@ G-Manは、を除きzsh`cat`は既に展開されます*(の$i展開がいくつかを`cat`導入する場合、引用符で囲まれていないワイルドカード(2回目のラウンド)を展開できます)。いずれにせよ、そのアプローチは確かに間違っています。
ステファンシャゼラス16

1
+1。各行にスペースなしで使用されているコマンドに必要な入力のみが含まれている場合、これは正常に機能します。
スビンセバスチャン

これは各単語に作用しますが、各行に作用するこの変形はありますか?
-thebunnyrules

問題は、ファイル名のリストを1行ずつ処理することでした。
ステフェンローラー

2
    sed "s/'/'\\\\''/g;s/.*/\$* '&'/" <<\FILE |\
    sh -s -- command echo --option
all of the{&}se li$n\es 'are safely shell
quoted and handed to command as its last argument
following --option, and, here, before that echo
FILE

出力

--option all of the{&}se li$n\es 'are safely shell
--option quoted and handed to command as its last argument
--option following --option, and, here, before that echo

-2
ed file.txt
%g/^/s// /
2,$g/^/-,.j
1s/^/command/
wq
chmod 755 file.txt
./file.txt

ファイルのすべての行を引数として単一のコマンドに渡します。つまり、

command line1 line2 line3 ....

--option各行の前にフラグが必要な場合は、2番目のコマンドを次のように変更します。

%g/^/s// --option /

1
ed ... reallyを実際に使用する場合、-1
user2217522 14年

3
私はあなたに反対票を投じませんでしたが、おそらくこれらの理由を持っていた人:(1)これは質問が求めることをしません。これにより、コマンドラインでファイルのすべての内容を使用してコマンドが1回呼び出されます。1行に1回ではなく。(2)これは、シェルに特別な文字(ファイル内にある可能性がある)を処理するために何も行いません。例えば、'"<>;、など(3)これは、不要な一時ファイルを作成します。(4)このようなことは一般に「ヒアドキュメント」で行われます。(5)edコマンドが不器用です。最初の2つのコマンドはに減らすことができる%s/^/ /%j
G-Manは「Reinstate Monica」と言う
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.