私はこのようなlinks.txtという名前のテキストファイルを持っています
link1
link2
link3
このファイルを1行ずつループして、すべての行で操作を実行したいと思います。 whileループを使用してこれを実行できることはわかっていますが、学習しているため、forループを使用することを考えました。私は実際にこのようなコマンド置換を使用しました
a=$(cat links.txt)
次に、このようなループを使用しました
for i in $a; do ###something###;done
また、私はこのようなことをすることができます
for i in $(cat links.txt); do ###something###; done
今私の質問は、変数aにcatコマンドの出力を代入すると、link1 link2とlink3の間の改行文字が削除され、スペースに置き換えられることです。
echo $a
出力
link1 link2 link3
そしてforループを使いました。コマンド置換を行うと、常に新しい行がスペースに置き換えられるのですか?
よろしく
シェルがコマンドの置換後に フィールド分割 を実行したため、改行が失われました。
POSIX コマンド置換 セクション:
シェルは、サブシェル環境(シェル実行環境を参照)でコマンドを実行し、コマンド置換(コマンドのテキストと囲みの "$()"またはバッククォート)をコマンドの標準出力に置き換えて、コマンド置換を拡張し、削除します。置換の最後にある1つ以上の文字のシーケンス。 出力の最後の前に埋め込まれた文字は削除されません。ただし、IFSの値と有効な引用符に応じて、フィールド区切り文字として扱われ、フィールド分割時に削除される場合があります。出力にnullバイトが含まれている場合の動作は規定されていません。
デフォルトのIFS
値(少なくともbash
内):
$ printf '%q\n' "$IFS"
$' \t\n'
あなたの場合、IFS
を設定したり、二重引用符を使用したりしないため、フィールド分割時に改行文字が削除されます。
改行を保存するには、たとえば、setting IFS
toを空にします。
$ IFS=
$ a=$(cat links.txt)
$ echo "$a"
link1
link2
link3
改行は特殊文字であるため、いくつかの時点で入れ替えられます。それらを保持するには、引用符を使用して、それらが常に解釈されるようにする必要があります。
$ a="$(cat links.txt)"
$ echo "$a"
link1
link2
link3
ここで、データを操作するときは常に引用符を使用したため、改行文字(\n
)は常にシェルによって解釈されるため、そのまま残りました。いつか使用するのを忘れると、これらの特殊文字は失われます。
スペースを含む行でループを使用する場合も、まったく同じ動作が発生します。たとえば、次のファイルがあるとします...
mypath1/file with spaces.txt
mypath2/filewithoutspaces.txt
出力は、引用符を使用するかどうかによって異なります。
$ for i in $(cat links.txt); do echo $i; done
mypath1/file
with
spaces.txt
mypath2/filewithoutspaces.txt
$ for i in "$(cat links.txt)"; do echo "$i"; done
mypath1/file with spaces.txt
mypath2/filewithoutspaces.txt
引用符を使用したくない場合は、シェルフィールドの区切り記号(IFS
)を変更するために使用できる特別なシェル変数があります。この区切り文字を改行文字に設定すると、ほとんどの問題が解消されます。
$ IFS=$'\n'; for i in $(cat links.txt); do echo $i; done
mypath1/file with spaces.txt
mypath2/filewithoutspaces.txt
完全を期すために、コマンド出力の置換に依存しない別の例を次に示します。しばらくして、read
ユーティリティの動作自体が原因で、ほとんどのユーザーはこの方法の方が信頼性が高いと考えていました。
$ cat links.txt | while read i; do echo $i; done
以下はread
のmanページからの抜粋です。
読み取りユーティリティは、標準入力から1行を読み取ります。
read
は1行ずつ入力を取得するので、スペースが表示されても分割されません。パイプを介してcat
の出力を渡すだけで、行を繰り返し処理します。
編集:他の回答やコメントから、cat
の使用に関して人々は非常に消極的であることがわかります。 jasonwryan がコメントで述べたように、シェルでファイルを読み取るよりproper方法は、ストリームリダイレクト(<
)、 val0x00ffの回答はこちら で確認できます。しかし、質問は「シェルプログラミングでファイルを読み取る/処理する方法」ではないため、私の答えはより焦点を当てています引用行動ではなく、残りの行動。
私の強調を加えるために、for
ループはwordsを反復します。あなたのファイルが:
one two
three four
次に、これはfour行を出力します。
for Word in $(cat file); do echo "$Word"; done
ファイルのlinesを反復するには、次のようにします。
while IFS= read -r line; do
# do something with "$line" <-- quoted almost always
done < file
Bashからread
を使用できます。 mapfile
も探します
while read -r link
do
printf '%s\n' "$link"
done < links.txt
またはmapfileを使用する
mapfile -t myarray < links.txt
for link in "${myarray[@]}"; do printf '%s\n' "$link"; done