Menggunakan untuk
for l in $()
melakukan pemisahan kata berdasarkan IFS:
$ for l in $(printf %b 'a b\nc'); do echo "$l"; done
a
b
c
$ IFS=$'\n'; for l in $(printf %b 'a b\nc'); do echo "$l"; done
a b
c
IFS tidak harus disetel kembali jika tidak digunakan nanti.
for l in $()
juga melakukan perluasan nama jalur:
$ printf %b 'a\n*\n' > file.txt
$ IFS=$'\n'
$ for l in $(<file.txt); do echo "$l"; done
a
file.txt
$ set -f; for l in $(<file.txt); do echo "$l"; done; set +f
a
*
Jika IFS=$'\n'
, umpan baris dihilangkan dan diciutkan:
$ printf %b '\n\na\n\nb\n\n' > file.txt
$ IFS=$'\n'; for l in $(<file.txt); do echo "$l"; done
a
b
$(cat file.txt)
(atau $(<file.txt)
) juga membaca seluruh file ke memori.
Menggunakan baca
Tanpa -r garis miring terbalik digunakan untuk kelanjutan baris dan dihapus sebelum karakter lain:
$ cat file.txt
\1\\2\
3
$ cat file.txt | while read l; do echo "$l"; done
1\23
$ cat file.txt | while read -r l; do echo "$l"; done
\1\\2\
3
Karakter di IFS dilucuti dari awal dan akhir baris tetapi tidak diciutkan:
$ printf %b '1 2 \n\t3\n' | while read -r l; do echo "$l"; done
1 2
3
$ printf %b ' 1 2 \n\t3\n' | while IFS= read -r l; do echo "$l"; done
1 2
3
Jika baris terakhir tidak diakhiri dengan baris baru, read tetapkan l padanya tetapi keluar sebelum isi loop:
$ printf 'x\ny' | while read l; do echo $l; done
x
$ printf 'x\ny' | while read l || [[ $l ]]; do echo $l; done
x
y
Jika while loop ada di dalam pipeline, itu juga ada di dalam subkulit, jadi variabel tidak terlihat di luarnya:
$ x=0; seq 3 | while read l; do let x+=l; done; echo $x
0
$ x=0; while read l; do let x+=l; done < <(seq 3); echo $x
6
$ x=0; x=8 | x=9; echo $x
0
for
loop tidak dirancang untuk mengulang "garis". Sebaliknya itu mengulang "kata-kata".
Terminologi singkat:"baris" adalah hal-hal yang dipisahkan oleh baris baru. "kata" adalah hal-hal yang dipisahkan oleh spasi (dan baris baru, antara lain). dalam bahasa bash "kata" disebut "bidang".
Cara idiomatis untuk mengulang baris adalah dengan menggunakan while
loop dalam kombinasi dengan read
.
ioscan -m dsf | while read -r line
do
printf '%s\n' "$line"
done
Perhatikan bahwa while loop berada dalam subkulit karena pipa. Ini dapat menyebabkan kebingungan dengan ruang lingkup variabel. Di bash, Anda dapat menyiasatinya dengan menggunakan substitusi proses.
while read -r line
do
printf '%s\n' "$line"
done < <(ioscan -m dsf)
lihat juga http://mywiki.wooledge.org/BashFAQ/024
Perulangan for memisahkan hal-hal yang akan diulang menggunakan karakter di $IFS
variabel sebagai pemisah. IFS adalah kependekan dari Internal Field Separator. Biasanya $IFS
berisi spasi, tab, dan baris baru. Itu berarti for
loop akan mengulang "kata", bukan melewati garis.
Jika Anda bersikeras menggunakan for loop untuk mengulang garis, Anda harus mengubah nilai $IFS
hanya untuk baris baru. Tetapi jika Anda melakukan ini, Anda harus menyimpan nilai lama $IFS
dan pulihkan setelah loop, karena banyak hal lain juga bergantung pada $IFS
.
OLDIFS="$IFS"
IFS=$'\n' # bash specific
for line in $(ioscan -m dsf)
do
printf '%s\n' "$line"
done
IFS="$OLDIFS"
di shell POSIX, yang tidak memiliki Kutipan ANSI-C ($'\n'
), Anda dapat melakukannya seperti ini:
IFS='
'
yaitu:letakkan baris baru yang sebenarnya di antara tanda kutip.
Alternatifnya, Anda dapat menggunakan subkulit untuk memuat perubahan ke $IFS
:
(
# changes to variables in the subshell stay in the subshell
IFS=$'\n'
for line in $(ioscan -m dsf)
do
printf '%s\n' "$line"
done
)
# $IFS is not changed outside of the subshell
Tapi hati-hati perintah dalam loop itu sendiri mungkin tergantung pada beberapa pengaturan waras untuk $IFS
. Maka Anda harus mengembalikan $IFS
sebelum menjalankan perintah dan atur lagi sebelum loop berikutnya atau semacamnya. Saya tidak menyarankan mengotak-atik $IFS
. Terlalu banyak perintah bergantung pada beberapa nilai waras di $IFS
dan mengubahnya adalah mimpi buruk tanpa akhir dari perburuan serangga yang tidak jelas.
Lihat juga:
- http://wiki.bash-hackers.org/syntax/ccmd/classic_for
- http://wiki.bash-hackers.org/commands/builtin/read
- http://mywiki.wooledge.org/IFS
- http://mywiki.wooledge.org/SubShell
- http://mywiki.wooledge.org/ProcessSubstitution