Parsing file teks yang dibatasi dalam bash sebagai argumen perintah

10

Saya memiliki file teks yang dipisah seperti ini:

field1,field2,field3 
xield1,xield2,xield3 
dield1,dield2,dield3 
gield1,gield2,gield3

Setiap kolom ini akan menjadi parameter untuk suatu program, dan saya ingin program dipanggil untuk setiap baris

Saya berharap untuk loop, seperti:

for $i in file
    command $field2 -x $field3 -PN -$field1 >> output
done

Apa cara terbaik untuk mencapai sesuatu seperti ini di bash?

Dekan
sumber
Apakah jumlah bidangnya konstan?
Joseph R.
@ JosephRR. ya mereka, selalu 3
Dean

Jawaban:

7
while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

Ini harus berfungsi jika jumlah bidang konstan. Alih-alih echomenggunakan perintah Anda.

coffeMug
sumber
Terima kasih, saya hanya mencoba ini tetapi sepertinya hanya berfungsi untuk baris pertama. Segera setelah sebuah perintah berhasil itu tidak mencoba yang berikutnya, jika gagal itu akan mencoba yang berikutnya ...
Dean
Bagaimana yang Anda maksud dengan sukses atau gagal? Apa perintahmu?
coffeMug
Saya kira perintah yang dia jalankan adalah membaca input standar sebelum perintah "read" dapat melakukannya.
plugwash
4

Anda harus menggunakan a whiledengan readbuilt-in:

while IFS= read -r line;do
    fields=($(printf "%s" "$line"|cut -d',' --output-delimiter=' ' -f1-))
    command "${fields[1]}" -x "${fields[2]}" ... # ${fields[1]} is field 2
done < your_file_here

Bagaimana ini bekerja?

  • The cutPernyataan mengambil garis dan membagi pada pembatas yang ditentukan oleh -d.
  • Ini --output-delimiteradalah karakter pemisah yang cutakan digunakan untuk menampilkan bidang yang dipilih, di sini kita memilih spasi sehingga kita dapat menempatkan bidang yang berbeda ke dalam array fields.
  • Akhirnya, kami ingin semua bidang (dari bidang 1 hingga akhir) dan di sanalah -f1-ikut bermain.
  • Sekarang Anda memiliki berbagai bidang yang disimpan dalam variabel array fields, Anda dapat mengakses bidang tertentu yang Anda inginkan dengan sintaks di ${field[number]}mana numbersatu kurang dari jumlah bidang sebenarnya yang Anda inginkan karena pengindeksan array berbasis nol di Bash.

Catatan

  • Ini akan gagal jika salah satu bidang Anda berisi spasi.

Untuk jumlah bidang yang konstan

Anda bisa melakukan sesuatu yang mirip dengan jawaban 1_CR :

while IFS= read -r line;do
    IFS=, read -r field1 field2 field3 <<-EOI
    $line
    EOI
    command "$field2" -x "$field3" ... 
done < your_file_here

Di atas, meskipun tampak lebih berisik, harus bekerja di shell yang sesuai dengan POSIX, bukan hanya Bash.

Joseph R.
sumber
Itu tidak membaca dalam file yang saya punya masalah dengan, itu memecah baris menjadi kolom.
Dean
@Dean Ya, maaf. Saya tidak memperhatikan. Sedang mengerjakan itu sekarang.
Joseph R.
@Dean Silakan lihat jawaban yang diperbarui. Saya akan menambahkan penjelasan segera.
Joseph R.
. @JosephR, mungkin untuk menghindari menggunakan alat eksternal untuk membelah dengan menetapkan IFSke nilai yang sesuai dalam readdoa
Iruvar
@ 1_CR Saya tahu, terima kasih. Saya baru saja membahasnya :)
Joseph R.
1

Anda bisa readmembagi setiap baris menjadi larik ,dengan mengatur secara IFStepat.

while IFS=, read -r -a input; do
 printf "%s\n" "${input[0]}" "${input[1]}"
done < input.txt

Jadi, dalam contoh di atas, Anda dapat mengakses setiap elemen array menggunakan indeksnya, mulai 0.

iruvar
sumber
1

Ini awksatu-kapal akan melakukan apa yang Anda inginkan:

awk -F, '{cmd="echo " $2 " -x " $3 " -PN " $1 ">> output";  system(cmd)}' f.txt

Ganti echodengan perintah Anda dan f.txtdengan file yang ingin Anda ulangi.

Penjelasan singkat: -F,akan ditetapkan ,sebagai pembatas. cmdmembangun perintah dan system(cmd)memanggil perintah.

mkc
sumber
1

gnu sed dapat digunakan juga.

sed infile -e 's!^\([^,]*\),\([^,]*\),\([^,]*\)$!command \1 -x \2 -PN \3!e' >> output

perhatikan penggunaan opsi e pada perintah s

Hildred
sumber