Saya memiliki file .txt berikut:
Marco
Paolo
Antonio
Saya ingin membacanya baris demi baris, dan untuk setiap baris saya ingin menetapkan nilai baris .txt ke suatu variabel. Misalkan variabel saya adalah $name
, alurnya adalah:
- Baca baris pertama dari file
- Tetapkan
$name
= "Marco" - Lakukan beberapa tugas dengan
$name
- Baca baris kedua dari file
- Tetapkan
$name
= "Paolo"
Jawaban:
Berikut ini membaca file yang diteruskan sebagai argumen baris demi baris:
Ini adalah bentuk standar untuk membaca baris dari file dalam satu lingkaran. Penjelasan:
IFS=
(atauIFS=''
) mencegah spasi spasi awalan / jejak.-r
mencegah backslash lolos dari ditafsirkan.Atau Anda bisa memasukkannya ke skrip pembantu file bash, contoh konten:
Jika di atas disimpan ke skrip dengan nama file
readfile
, itu dapat dijalankan sebagai berikut:Jika file tersebut bukan file teks POSIX standar (= tidak diakhiri oleh karakter baris baru), loop dapat dimodifikasi untuk menangani trailing sebagian baris:
Di sini,
|| [[ -n $line ]]
mencegah baris terakhir dari diabaikan jika tidak diakhiri dengan\n
(karenaread
mengembalikan kode keluar non-nol ketika bertemu EOF).Jika perintah-perintah di dalam loop juga membaca dari input standar, deskriptor file yang digunakan oleh
read
bisa kebetulan ke yang lain (hindari deskriptor file standar ), misal:(Kerang Non-Bash mungkin tidak tahu
read -u3
; gunakanread <&3
saja.)sumber
ssh
tanpa-n
bendera akan secara efektif menyebabkan Anda lolos dari loop. Mungkin ada alasan bagus untuk ini, tetapi perlu beberapa saat untuk menentukan apa yang menyebabkan kode saya gagal sebelum saya menemukan ini.ffmpeg
konsumsi stdin. Tambahkan</dev/null
keffmpeg
baris Anda dan itu tidak akan bisa, atau menggunakan FD alternatif untuk loop. Pendekatan "alternatif FD" itu sepertiwhile IFS='' read -r line <&3 || [[ -n "$line" ]]; do ...; done 3<"$1"
..sh
ekstensi. Executables di UNIX biasanya tidak memiliki ekstensi sama sekali (Anda tidak menjalankanls.elf
), dan memiliki bash shebang (dan bash-only tooling seperti[[ ]]
) dan ekstensi yang menyiratkan kompatibilitas POSIX sh secara internal bertentangan.Saya mendorong Anda untuk menggunakan
-r
benderaread
yang merupakan kependekan dari:Saya mengutip dari
man 1 read
.Hal lain adalah mengambil nama file sebagai argumen.
Berikut kode yang diperbarui:
sumber
sh
tidakbash
; perintah tes diperpanjang yang digunakan dalam|| [[ -n "$line" ]]
sintaks dalam jawaban yang diterima adalah bashism. Yang mengatakan, sintaksis itu sebenarnya memiliki makna yang relevan: Itu menyebabkan loop untuk melanjutkan untuk baris terakhir dalam file input bahkan jika itu tidak memiliki baris baru. Jika Anda ingin melakukannya dengan cara yang sesuai dengan POSIX, Anda ingin|| [ -n "$line" ]
, menggunakan[
daripada[[
.IFS=
untukread
mencegah pemangkasan spasi.Menggunakan templat Bash berikut akan memungkinkan Anda membaca satu nilai pada satu waktu dari suatu file dan memprosesnya.
sumber
*
.sumber
Enter
setelah baris terakhir), jika tidak, baris terakhir akan diabaikan. Setidaknya itulah yang terjadi pada saya.Banyak orang memposting solusi yang terlalu dioptimalkan. Saya tidak berpikir itu salah, tetapi saya dengan rendah hati berpikir bahwa solusi yang kurang dioptimalkan akan diinginkan untuk memungkinkan semua orang dengan mudah memahami bagaimana ini bekerja. Ini proposal saya:
sumber
Menggunakan:
Jika Anda menetapkan
IFS
berbeda, Anda akan mendapatkan hasil yang aneh.sumber
*
pada satu baris? Bagaimanapun, ini adalah antipattern . Jangan baca baris dengan untuk .read
pendekatan ini adalah pendekatan praktik terbaik dengan konsensus komunitas . Peringatan yang Anda sebutkan dalam komentar Anda adalah salah satu yang berlaku ketika loop Anda menjalankan perintah (sepertiffmpeg
) yang membaca dari stdin, diselesaikan secara sepele dengan menggunakan FD non-stdin untuk loop atau mengarahkan input perintah tersebut. Sebaliknya, mengatasi bug globbing dalamfor
pendekatan -loop Anda berarti membuat (dan kemudian perlu membalikkan) perubahan pengaturan global shell.for
pendekatan loop yang Anda gunakan di sini berarti bahwa semua konten harus dibaca sebelum loop dapat mulai dijalankan sama sekali, menjadikannya sama sekali tidak dapat digunakan jika Anda mengulang-ulang gigabyte data bahkan jika Anda telah menonaktifkan globbing; yangwhile read
lingkaran perlu menyimpan tidak lebih dari data yang satu baris pada satu waktu, yang berarti dapat mulai mengeksekusi sedangkan konten pembangkit sub proses masih berjalan (sehingga menjadi dapat digunakan untuk tujuan mengalir), dan juga memiliki konsumsi memori terbatas.while
pendekatan berbasis tampaknya memiliki * masalah karakter. Lihat komentar dari jawaban yang diterima di atas. Namun, tidak membantah iterasi atas file sebagai antipattern.Jika Anda perlu memproses file input dan input pengguna (atau apa pun dari stdin), maka gunakan solusi berikut:
Berdasarkan jawaban yang diterima dan pada tutorial pengalihan bash-hacker .
Di sini, kami membuka file deskriptor 3 untuk file yang dikirimkan sebagai argumen skrip dan meminta
read
untuk menggunakan deskriptor ini sebagai input (-u 3
). Dengan demikian, kita membiarkan deskriptor input default (0) melekat pada terminal atau sumber input lain, dapat membaca input pengguna.sumber
Untuk penanganan kesalahan yang tepat:
sumber
Berikut ini hanya akan mencetak konten file:
sumber
Gunakan alat IFS (pemisah bidang internal) di bash, tentukan karakter yang digunakan untuk memisahkan garis menjadi token, secara default termasuk < tab > / < space > / < newLine >
langkah 1 : Muat data file dan masukkan ke dalam daftar:
langkah 2 : sekarang iterate dan cetak output:
gema indeks spesifik dalam array : Mengakses ke variabel dalam array:
sumber