GNU/Linux >> Belajar Linux >  >> Linux

Ulangi baris alih-alih kata-kata dalam for loop skrip Shell

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

Linux
  1. 12 Contoh Bash For Loop untuk Scripting Shell Linux Anda

  2. Format tanggal dan waktu untuk skrip atau variabel shell Linux

  3. konvensi penamaan untuk skrip shell dan makefile

  1. Ssh – Skrip Shell Untuk Masuk Ke Server Ssh?

  2. Skrip Bash:Menggunakan perintah skrip dari skrip bash untuk mencatat sesi

  3. Bagaimana saya bisa mengulang output dari perintah shell?

  1. Script Shell Untuk Memindahkan File Terlama?

  2. Panduan Eksekusi Skrip Shell untuk Pemula

  3. Cara mencari file menggunakan regex di skrip shell linux