Saya memiliki file teks:
1 Q0 1657 1 19.6117 Exp
1 Q0 1410 2 18.8302 Exp
2 Q0 3078 1 18.6695 Exp
2 Q0 2434 2 14.0508 Exp
2 Q0 3129 3 13.5495 Exp
Saya ingin mengambil kata ke-2 dan ke-4 dari setiap baris seperti ini:
1657 19.6117
1410 18.8302
3078 18.6695
2434 14.0508
3129 13.5495
Saya menggunakan kode ini:
nol=$(cat "/path/of/my/text" | wc -l)
x=1
while [ $x -le "$nol" ]
do
line=($(sed -n "$x"p /path/of/my/text)
echo ""${line[1]}" "${line[3]}"" >> out.txt
x=$(( $x + 1 ))
done
Ini berfungsi, tetapi sangat rumit dan membutuhkan waktu lama untuk memproses file teks yang panjang.
Apakah ada cara yang lebih sederhana untuk melakukan ini?
Jawaban:
iirc:
cat filename.txt | awk '{ print $2 $4 }'
atau, seperti yang disebutkan di komentar:
awk '{ print $2 $4 }' filename.txt
sumber
awk '{print $2,$4}' filename.txt
lebih baik (tidak ada pipa, hanya satu program yang dipanggil)cat
skrip bash saya daripada menentukan nama file, karena overhead minimal dan karena sintakscat ... | ... > ...
menunjukkan dengan sangat baik apa input dan ke mana output pergi. Anda benar, sebenarnya tidak diperlukan di sini.< input awk '{ print $2 $4 }' > output
untuk tujuan itu.Anda dapat menggunakan
cut
perintah:cut -d' ' -f3,5 < datafile.txt
cetakan
itu
-d' '
- maksudnya, gunakanspace
sebagai pembatas-f3,5
- ambil dan cetak kolom ke-3 dan ke-5The
cut
adalah jauh lebih cepat untuk file besar sebagai solusi shell murni. Jika file Anda dibatasi dengan beberapa spasi, Anda dapat menghapusnya terlebih dahulu, seperti:sed 's/[\t ][\t ]*/ /g' < datafile.txt | cut -d' ' -f3,5
di mana (gnu) sed akan mengganti karakter
tab
atauspace
dengan satuspace
.Untuk varian - berikut adalah solusi perl juga:
perl -lanE 'say "$F[2] $F[4]"' < datafile.txt
sumber
Demi kelengkapan:
while read _ _ one _ two _; do echo "$one $two" done < file.txt
Alih-alih
_
variabel arbitrer (sepertijunk
) dapat digunakan juga. Intinya adalah mengekstrak kolom.Demo:
$ while read _ _ one _ two _; do echo "$one $two"; done < /tmp/file.txt 1657 19.6117 1410 18.8302 3078 18.6695 2434 14.0508 3129 13.5495
sumber
Satu varian yang lebih sederhana -
$ while read line do set $line # assigns words in line to positional parameters echo "$3 $5" done < file
sumber
Jika file Anda berisi n baris, maka skrip Anda harus membaca file n sebanyak kali; jadi jika Anda menggandakan panjang file, Anda melipatgandakan jumlah pekerjaan yang dilakukan skrip Anda - dan hampir semua pekerjaan itu dibuang begitu saja, karena yang ingin Anda lakukan hanyalah mengulang baris secara berurutan.
Sebaliknya, cara terbaik untuk mengulang baris file adalah dengan menggunakan
while
loop, dengan perintah kondisi sebagairead
bawaannya:while IFS= read -r line ; do # $line is a single line of the file, as a single string : ... commands that use $line ... done < input_file.txt
Dalam kasus Anda, karena Anda ingin membagi baris menjadi array, dan
read
builtin sebenarnya memiliki dukungan khusus untuk mengisi variabel array, yang Anda inginkan, Anda dapat menulis:while read -r -a line ; do echo ""${line[1]}" "${line[3]}"" >> out.txt done < /path/of/my/text
atau lebih baik lagi:
while read -r -a line ; do echo "${line[1]} ${line[3]}" done < /path/of/my/text > out.txt
Namun, untuk apa yang Anda lakukan, Anda dapat menggunakan
cut
utilitas:cut -d' ' -f2,4 < /path/of/my/text > out.txt
(atau
awk
, seperti yang disarankan Tom van der Woerdt, atauperl
, atau bahkansed
).sumber
read
lebihcut
karena kuat melawan banyak spasi antara bidang dan Anda tidak memerlukan sihir array:while read word1 word2 word3 word4 rest; do doSomethingWith $word2 $word4; done
Jika Anda menggunakan data terstruktur, manfaat tambahannya adalah tidak meminta proses shell ekstra untuk dijalankan
tr
dan /cut
atau semacamnya. ...(Tentu saja, Anda ingin berhati-hati terhadap masukan yang buruk dengan kondisional dan alternatif yang masuk akal.)
... while read line ; do lineCols=( $line ) ; echo "${lineCols[0]}" echo "${lineCols[1]}" done < $myFQFileToRead ; ...
sumber