ファイルの行をループする方法は?

このファイルがあるとしましょう:

hello world hello world 

このプログラム

#!/bin/bash for i in $(cat $1); do echo "tester: $i" done 

出力

tester: hello tester: world tester: hello tester: world 

forは、空白を無視して各行を個別に繰り返します。つまり、最後の2行は次のように置き換える必要があります

tester: hello world 

引用符を使用for i in "$(cat $1)";の結果iにファイル全体が一度に割り当てられます。何を変更すればよいですか?

回答

(9年後:)
提供された両方の回答は、最後に新しい行がないファイルでは失敗します。これにより、最後の行が事実上スキップされ、エラーが発生せず、災害につながります(一生懸命学習しました)方法:)。

これまでに見つけた「JustWorks」(bashとshの両方)の最も簡潔なソリューション:

while IFS="" read -r LINE || [ -n "${LINE}" ]; do echo "processing line: ${LINE}" done < /path/to/input/file.txt 

より詳細な説明については、次のStackOverflowの説明を参照してください:使用方法 “whileファイルの最後に改行がない場合にファイルの最後の行を読み取るには、「read」(Bash)を使用しますか?

注意:このアプローチでは、最後の行に改行がある場合に追加の改行が追加されます。まだありません。

コメント

  • いいですね、ありがとうございます。 "まだ改行がない場合は、EOFに改行が追加されることに注意してください。" コメントですが
  • トビアス、私は'これをメモとして追加します、ありがとうございます。

回答

forおよび IFSを使用

#!/bin/bash IFS=$"\n" # make newlines the only separator set -f # disable globbing for i in $(cat < "$1"); do echo "tester: $i" done 

ただし、改行はIFS空白文字であるため、空の行はスキップされることに注意してください。そのうちの1つは1としてカウントされ、先頭と末尾のものは無視されます。 zshksh93bashではない)を使用すると、

改行を特別に処理しないようにします。ただし、すべての末尾改行文字(末尾の空行を含む)は、コマンド置換によって常に削除されることに注意してください。

またはread (これ以上cat ):

#!/bin/bash while IFS= read -r line; do echo "tester: $line" done < "$1" 

空の行は保持されますが、改行文字で適切に区切られていない場合、最後の行がスキップされることに注意してください。

コメント

  • ありがとう、' <をループ全体に。今では完全に理にかなっていますが
  • IFS \ read -r line' in second example. Is really IFS = `が必要ですか? while read -r line; do echo "tester: $line"; done < "$1"
  • @GrzegorzWierzowiecki IFS=は、先頭と末尾の空白の削除をオフにします。 while IFS= read..で、IFSが効果を発揮しないのはなぜですか?
  • @BenMaresグロブを防ぐため読んでいるテキストに、展開されて一致するファイル名に表示される可能性のある式。たとえば、printf '%s\n' '*o' 'bar' >afile; touch foo; IFS=$'\n'; for i in $(cat afile); do echo "$i"; doneを試してください。
  • while IFS= read -r line || [ "$line" ]; doは、改行文字で適切に区切られていない末尾の行を処理します。 (ただし、追加されます)。

回答

その価値については、次のことを行う必要があります。これは非常に頻繁であり、while IFS= read...の正確な使用方法を思い出せないため、bashプロファイルで次の関数を定義しました。

# iterate the line of a file and call input function iterlines() { (( $# < 2 )) && { echo "Usage: iterlines <File> <Callback>"; return; } local File=$1 local Func=$2 n=$(cat "$File" | wc -l) for (( i=1; i<=n; i++ )); do "$Func" "$(sed "${i}q;d" "$File")" done } 

この関数は、最初にファイル内の行数を決定し、次にsedを使用して行を次々に抽出し、各行を単一の文字列引数として任意の行に渡します関数。これは大きなファイルでは本当に非効率になるかもしれないと思いますが、これまでのところ問題にはなりませんでした(もちろん、この歓迎を改善する方法についての提案)。

使用法はかなり甘いIMOです:

>> cat example.txt # note the use of spaces, whitespace, etc. a/path This is a sentence. "wi\th quotes" $End >> iterlines example.txt echo # preserves quotes, $ and whitespace a/path This is a sentence. "wi\th quotes" $End >> x() { echo "$#"; }; iterlines example.txt x # line always passed as single input string 1 1 1 1 1 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です