Bagaimana cara saya mengulangi setiap baris file teks dengan Bash ?
Dengan skrip ini:
echo "Start!"
for p in (peptides.txt)
do
echo "${p}"
done
Saya mendapatkan output ini di layar:
Start!
./runPep.sh: line 3: syntax error near unexpected token `('
./runPep.sh: line 3: `for p in (peptides.txt)'
(Nanti saya ingin melakukan sesuatu yang lebih rumit $p
dari sekedar output ke layar.)
Variabel lingkungan SHELL adalah (dari env):
SHELL=/bin/bash
/bin/bash --version
keluaran:
GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
cat /proc/version
keluaran:
Linux version 2.6.18.2-34-default (geeko@buildhost) (gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)) #1 SMP Mon Nov 27 11:46:27 UTC 2006
File peptides.txt berisi:
RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL
Jawaban:
Salah satu cara untuk melakukannya adalah:
Seperti yang ditunjukkan dalam komentar, ini memiliki efek samping memangkas spasi putih terkemuka, menafsirkan urutan backslash, dan melewatkan baris terakhir jika tidak ada linefeed terminasi. Jika ini masalah, Anda dapat melakukan:
Khususnya, jika badan loop dapat membaca dari input standar , Anda dapat membuka file menggunakan deskriptor file yang berbeda:
Di sini, 10 hanyalah angka acak (berbeda dari 0, 1, 2).
sumber
while read p || [[ -n $p ]]; do ...
dan varian satu-baris:
Opsi-opsi ini akan melewati baris terakhir file jika tidak ada umpan garis tertinggal.
Anda dapat menghindari ini dengan yang berikut:
sumber
Opsi 1a: Loop sementara: Satu baris sekaligus: Pengalihan input
Opsi 1b: Sementara loop: Baris tunggal pada satu waktu:
Buka file, baca dari deskriptor file (dalam hal ini file deskriptor # 4).
sumber
done < $filename
dengandone 4<$filename
(yang berguna jika Anda ingin membaca nama file dari parameter perintah, dalam hal ini Anda bisa mengganti$filename
dengan$1
).tail -n +2 myfile.txt | grep 'somepattern' | cut -f3
, ketika menjalankan perintah ssh di dalam loop (mengkonsumsi stdin); opsi 2 di sini tampaknya menjadi satu-satunya cara?Ini tidak lebih baik daripada jawaban lain, tetapi merupakan satu lagi cara untuk menyelesaikan pekerjaan dalam file tanpa spasi (lihat komentar). Saya menemukan bahwa saya sering perlu satu baris untuk menggali daftar dalam file teks tanpa langkah tambahan menggunakan file skrip yang terpisah.
Format ini memungkinkan saya untuk meletakkan semuanya dalam satu baris perintah. Ubah bagian "echo $ word" menjadi apa pun yang Anda inginkan dan Anda dapat mengeluarkan beberapa perintah yang dipisahkan oleh titik koma. Contoh berikut menggunakan konten file sebagai argumen ke dua skrip lain yang mungkin Anda tulis.
Atau jika Anda bermaksud untuk menggunakan ini seperti editor aliran (pelajari sed) Anda dapat membuang output ke file lain sebagai berikut.
Saya telah menggunakan ini seperti yang ditulis di atas karena saya telah menggunakan file teks di mana saya membuatnya dengan satu kata per baris. (Lihat komentar) Jika Anda memiliki spasi yang tidak ingin Anda pisahkan kata-kata / kalimat Anda, itu akan menjadi sedikit lebih buruk, tetapi perintah yang sama masih berfungsi sebagai berikut:
Ini hanya memberitahu shell untuk membagi pada baris baru saja, bukan spasi, lalu mengembalikan lingkungan kembali ke apa yang sebelumnya. Pada titik ini, Anda mungkin ingin mempertimbangkan untuk memasukkan semuanya ke dalam skrip shell daripada meremasnya menjadi satu baris.
Semoga berhasil!
sumber
for
membuat token input / garis tunduk pada ekspansi shell, yang biasanya tidak diinginkan; coba ini:for l in $(echo '* b c'); do echo "[$l]"; done
- seperti yang akan Anda lihat,*
- meskipun awalnya literal yang dikutip - diperluas ke file dalam direktori saat ini.for
untuk mengulangi baris file adalah ide yang buruk. Plus, aspek ekspansi disebutkan oleh @ mklement0 (meskipun itu mungkin dapat dielakkan dengan membawa tanda kutip yang lolos, yang lagi-lagi membuat hal-hal menjadi lebih kompleks dan kurang dapat dibaca).Beberapa hal lagi yang tidak dicakup oleh jawaban lain:
Membaca dari file yang dibatasi
Membaca dari output perintah lain, menggunakan proses substitusi
Pendekatan ini lebih baik daripada
command ... | while read -r line; do ...
karena loop sementara di sini berjalan di shell saat ini daripada subkulit seperti dalam kasus yang terakhir. Lihat posting terkait Variabel yang diubah dalam loop sementara tidak diingat .Membaca dari input terbatas nol, misalnya
find ... -print0
Terkait baca: BashFAQ / 020 - Bagaimana saya bisa menemukan dan dengan aman menangani nama file yang mengandung baris baru, spasi atau keduanya?
Membaca dari lebih dari satu file sekaligus
Berdasarkan jawaban @ chepner di sini :
-u
adalah ekstensi bash. Untuk kompatibilitas POSIX, setiap panggilan akan terlihat sepertiread -r X <&3
.Membaca seluruh file menjadi sebuah array (versi Bash sebelumnya ke 4)
Jika file berakhir dengan baris yang tidak lengkap (baris baru hilang di bagian akhir), maka:
Membaca seluruh file menjadi sebuah array (Bash versi 4x dan yang lebih baru)
atau
Lalu
Lebih lanjut tentang shell builtin
read
danreadarray
perintah - GNULebih lanjut tentang
IFS
- WikipediaPosting terkait:
sumber
command < input_filename.txt
Anda selalu dapat melakukaninput_generating_command | command
ataucommand < <(input_generating_command)
Gunakan loop sementara, seperti ini:
Catatan:
Jika Anda tidak mengatur dengan
IFS
benar, Anda akan kehilangan lekukan.Anda hampir selalu harus menggunakan opsi -r dengan membaca.
Jangan membaca baris dengan
for
sumber
-r
pilihan?Note #2
adalah tautan yang dijelaskan secara terperinci ...-u
opsi, apakah Anda berbicara tentang contoh lain dengan-u
?Misalkan Anda memiliki file ini:
Ada empat elemen yang akan mengubah arti dari output file yang dibaca oleh banyak solusi Bash:
Jika Anda ingin file teks baris demi baris termasuk baris kosong dan mengakhiri baris tanpa CR, Anda harus menggunakan loop sementara dan Anda harus memiliki tes alternatif untuk baris terakhir.
Berikut adalah metode yang dapat mengubah file (dibandingkan dengan apa yang
cat
kembali):1) Kehilangan baris terakhir dan spasi terdepan dan tertinggal:
(Jika Anda melakukannya
while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
, Anda mempertahankan spasi di depan dan di belakang tetapi masih kehilangan baris terakhir jika tidak diakhiri dengan CR)2) Menggunakan proses substitusi dengan
cat
akan membaca seluruh file dalam satu tegukan dan kehilangan arti dari setiap baris:(Jika Anda menghapus
"
dari$(cat /tmp/test.txt)
Anda membaca file kata demi kata daripada satu tegukan. Juga mungkin bukan apa yang dimaksudkan ...)Cara paling kuat dan paling sederhana untuk membaca file baris demi baris dan mempertahankan semua spasi adalah:
Jika Anda ingin menghapus ruang utama dan perdagangan, hapus
IFS=
bagian tersebut:(File teks tanpa terminasi
\n
, sementara cukup umum, dianggap rusak di bawah POSIX. Jika Anda dapat mengandalkan trailing,\n
Anda tidak perlu|| [[ -n $line ]]
dalamwhile
loop.)Lebih banyak di BASH FAQ
sumber
Jika Anda tidak ingin bacaan Anda rusak oleh karakter baris baru, gunakan -
Kemudian jalankan skrip dengan nama file sebagai parameter.
sumber
sumber
Berikut ini adalah contoh kehidupan nyata saya bagaimana untuk loop garis dari output program lain, periksa substring, drop tanda kutip ganda dari variabel, gunakan variabel itu di luar loop. Saya kira cukup banyak yang menanyakan pertanyaan ini cepat atau lambat.
Deklarasikan variabel di luar loop, atur nilai dan gunakan di luar loop yang harus dilakukan dengan sintaks <<< "$ (...)" . Aplikasi perlu dijalankan dalam konteks konsol saat ini. Kutipan di sekitar perintah menjaga baris arus keluaran baru.
Lingkaran yang cocok untuk substring kemudian membaca nama = pasangan nilai , membagi bagian sisi kanan dari karakter = terakhir , menjatuhkan kutipan pertama, menjatuhkan kutipan terakhir, kami memiliki nilai bersih untuk digunakan di tempat lain.
sumber
Ini datang agak terlambat, tetapi dengan pemikiran bahwa itu dapat membantu seseorang, saya menambahkan jawabannya. Juga ini mungkin bukan cara terbaik.
head
perintah dapat digunakan dengan-n
argumen untuk membaca n baris dari awal file dan jugatail
perintah dapat digunakan untuk membaca dari bawah. Sekarang, untuk mengambil baris ke-n dari file, kita menuju n baris , menyalurkan data ke ekor hanya 1 baris dari data yang disalurkan.sumber
sed
atauhead
+tail
adalah sangat tidak efisien, dan tentu saja menimbulkan pertanyaan mengapa Anda tidak hanya menggunakan salah satu solusi lain di sini. Jika Anda perlu mengetahui nomor baris, tambahkan penghitung kewhile read -r
loop Anda , atau gunakannl -ba
untuk menambahkan awalan nomor baris ke setiap baris sebelum loop.@ Peter: Ini bisa berhasil untuk Anda-
Ini akan mengembalikan output-
sumber