web-dev-qa-db-ja.com

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

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

44
WojciechF

while readループを使用します。

: > another_file  ## Truncate file.

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

もう1つは、ブロックごとに出力をリダイレクトすることです。

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を使用することをお勧めします(ここでは、-u 3に対してkshzshまたはbashを想定し、代わりに移植性のある<&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
konsolebox

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

GNU xargs

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

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

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

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

Unix準拠のシステム(-IはPOSIXではオプションであり、Unix準拠のシステムでのみ必要です)、入力を前処理する必要がありますquotexargsが予期する形式の行:

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

ただし、一部のxargs実装では、引数の最大サイズに非常に低い制限があります(Solarisでは255、Unix仕様で許可されている最小など)。

29
ctrl-alt-delor

質問に正確に従う:

#!/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
9
miigotu

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

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

編集:

... 4年後 ...

いくつかの反対投票といくつかのより多くの経験の後、私は今以下をお勧めします

xargs -l COMMAND < file
5
Steffen Roller
    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
mikeserv