Bagaimana cara membuat perintah 'cut' memperlakukan pembatas sekuensial yang sama sebagai satu?

309

Saya mencoba untuk mengekstrak bidang (keempat) tertentu dari aliran teks yang disesuaikan dengan spasi, yang disesuaikan dengan kolom. Saya mencoba menggunakan cutperintah dengan cara berikut:

cat text.txt | cut -d " " -f 4

Sayangnya, cuttidak memperlakukan beberapa ruang sebagai satu pembatas. Saya bisa menyalurkan melalui awk

awk '{ printf $4; }'

atau sed

sed -E "s/[[:space:]]+/ /g"

untuk meruntuhkan ruang, tapi saya ingin tahu apakah ada cara untuk menangani cutdan beberapa pembatas secara asli?

mbaitoff
sumber
12
AWK adalah cara untuk pergi.
Dijeda sampai pemberitahuan lebih lanjut.

Jawaban:

546

Mencoba:

tr -s ' ' <text.txt | cut -d ' ' -f4

Dari trhalaman manual:

-s, --squeeze-repeats menggantikan setiap urutan input dari karakter yang diulang
                        yang tercantum dalam SET1 dengan kejadian tunggal
                        karakter itu
kev
sumber
24
Tidak perlu di catsini. Anda dapat mengirim < text.txtlangsung ke tr. en.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat
arielf
1
Tidak yakin itu lebih sederhana, tetapi Anda akan bergabung, Anda dapat melupakan cut -ddan menerjemahkan langsung dari beberapa karakter ke tab. Sebagai contoh: Saya datang ke sini mencari cara untuk secara otomatis mengekspor tampilan saya:who am i | tr -s ' ()' '\t' | cut -f5
Leo
Ini tidak menghapus spasi spasi awal / akhir (yang mungkin atau mungkin tidak diinginkan, tetapi biasanya tidak), berbeda dengan solusi awk. Solusi awk juga jauh lebih mudah dibaca dan kurang bertele-tele.
n.caillou
-1 PERINGATAN: INI BUKAN HAL YANG SAMA SEBAGAI PERAWATAN PENGUASA SEQUENTIAL SEBAGAI SATU. Bandingkan echo "a b c" | cut -d " " -f2-,echo "a b c" | tr -s " " | cut -d " " -f2-
user541686
96

Saat Anda mengomentari pertanyaan Anda, awkini benar-benar cara yang harus ditempuh. Untuk menggunakan cutdimungkinkan bersama dengan tr -smenekan spasi, seperti yang ditunjukkan oleh kev .

Namun, biarkan saya membaca semua kombinasi yang mungkin untuk pembaca di masa mendatang. Penjelasan ada di bagian Uji.

tr | memotong

tr -s ' ' < file | cut -d' ' -f4

awk

awk '{print $4}' file

pesta

while read -r _ _ _ myfield _
do
   echo "forth field: $myfield"
done < file

sed

sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file

Tes

Diberikan file ini, mari kita coba perintah:

$ cat a
this   is    line     1 more text
this      is line    2     more text
this    is line 3     more text
this is   line 4            more    text

tr | memotong

$ cut -d' ' -f4 a
is
                        # it does not show what we want!


$ tr -s ' ' < a | cut -d' ' -f4
1
2                       # this makes it!
3
4
$

awk

$ awk '{print $4}' a
1
2
3
4

pesta

Ini membaca bidang secara berurutan. Dengan menggunakan _kami menunjukkan bahwa ini adalah variabel yang dapat dibuang sebagai "variabel sampah" untuk mengabaikan bidang ini. Dengan cara ini, kami menyimpan $myfieldsebagai bidang ke-4 dalam file, tidak peduli ruang di antaranya.

$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4

sed

Ini menangkap tiga kelompok ruang dan tidak ada ruang dengan ([^ ]*[ ]*){3}. Kemudian, ia menangkap apa pun yang datang sampai ruang sebagai bidang ke-4, yang akhirnya dicetak bersama \1.

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4
fedorqui 'SO berhenti merugikan'
sumber
2
awktidak hanya elegan dan sederhana, itu juga termasuk dalam VMware ESXi, di mana trhilang.
user121391
2
@ user121391 alasan lain untuk digunakan awk!
fedorqui 'SO stop harming'
@ fedorqui Saya belum pernah mendengar garis bawah sebagai "variabel sampah". Bisakah Anda memberikan wawasan / referensi lebih lanjut tentang ini?
BryKKan
1
@BryKKan saya mempelajarinya di Greg's Bagaimana saya bisa membaca file (aliran data, variabel) baris demi baris (dan / atau bidang-demi-bidang)? : Beberapa orang menggunakan variabel throwaway _ sebagai "variabel sampah" untuk mengabaikan bidang. Itu (atau memang variabel apa pun) juga dapat digunakan lebih dari sekali dalam satu readperintah, jika kita tidak peduli apa yang masuk ke dalamnya . Itu bisa apa saja, hanya saja entah bagaimana itu menjadi standar alih-alih junk_varatau whatever:)
fedorqui 'SO stop harming'
25

solusi terpendek / ramah

Setelah menjadi frustrasi dengan terlalu banyak keterbatasan cut, saya menulis pengganti saya sendiri, yang saya sebut cuts"cut on steroids".

pemotongan memberikan apa yang kemungkinan merupakan solusi paling minimalis untuk masalah ini dan banyak masalah terkait lainnya

Satu contoh, dari banyak, menjawab pertanyaan khusus ini:

$ cat text.txt
0   1        2 3
0 1          2   3 4

$ cuts 2 text.txt
2
2

cuts mendukung:

  • deteksi otomatis dari bidang-pembatas paling umum dalam file (+ kemampuan untuk menimpa default)
  • pembatas multi-char, mixed-char, dan regex yang cocok
  • mengekstraksi kolom dari banyak file dengan pembatas campuran
  • offset dari ujung jalur (menggunakan angka negatif) selain dari awal jalur
  • menempel kolom secara otomatis berdampingan (tidak perlu meminta pastesecara terpisah)
  • dukungan untuk penataan ulang bidang
  • file konfigurasi tempat pengguna dapat mengubah preferensi pribadi mereka
  • penekanan besar pada keramahan pengguna & pengetikan diperlukan minimalis

dan banyak lagi. Tidak ada yang disediakan oleh standar cut.

Lihat juga: https://stackoverflow.com/a/24543231/1296044

Sumber dan dokumentasi (perangkat lunak gratis): http://arielf.github.io/cuts/

diri sendiri
sumber
4

Perl one-liner ini menunjukkan seberapa dekat Perl terkait dengan awk:

perl -lane 'print $F[3]' text.txt

Namun, @Flarik autosplit dimulai pada indeks $F[0]sementara bidang awk mulai dengan$1

Chris Koknat
sumber
3

Dengan versi yang cutsaya tahu, tidak, ini tidak mungkin. cutterutama berguna untuk mem-parsing file di mana pemisah tidak spasi putih (misalnya /etc/passwd) dan yang memiliki jumlah bidang tetap. Dua pemisah dalam satu baris berarti bidang kosong, dan itu berlaku juga untuk spasi putih.

Benoit
sumber