Apa yang harus saya gunakan ketika potongan tidak dipotong?

19

Saya punya file citiesseperti ini:

[1598] San Diego, US (inactive)
[4517] St Louis, US (inactive)
[6346] Orlando, US (inactive)

Saya ingin memotong nama kota, sehingga saya memiliki:

San Diego
St Louis
Orlando

Ini yang terbaik yang bisa saya pikirkan:

cut -d ',' -f1 cities | cut -d ']' -f2

Tapi itu masih memberi saya ruang sebelum nama. Apakah ada cutperintah sejenis yang bisa saya gunakan yang menerima pembatas beberapa karakter sehingga saya bisa memotong ]?

Kit Sunde
sumber
1
trberguna untuk menghapus karakter yang tidak Anda inginkan.
LawrenceC
Jika Anda mencoba kode dalam jawaban orang, Anda akan melihat tiga keluaran berbeda. Ini menunjukkan bahwa pertanyaan Anda tidak 100% jelas. Apakah "cut out" berarti menghapus atau memilih? Anda ingin (inactive)statusnya atau tidak? Harap berikan output sampel.
Mikel
@Mikel - Mempertimbangkan saya menggunakan cutuntuk memotong sesuatu dan Anda dapat melihat maksud dari contoh gagal yang saya miliki, itu harus cukup jelas dalam konteksnya. Saya akan memberikan sampel meskipun untuk menjernihkannya lebih lanjut. :)
Kit Sunde
Tidak terlalu. Saya mengubah satu kalimat dalam pertanyaan Anda menjadi "hanya mencetak nama kota", karena Anda menggunakan kata "cut" yang tidak jelas bagi saya. Apakah perubahan saya benar?
Mikel
1
@Kit Sunde: Dengan output sampel, tentu bisa dimengerti. Judulnya lucu. "cut out" membuat saya berpikir tentang apa yang terjadi ketika Anda menekan Ctrl + X, itulah sebabnya saya menyarankan perubahan, tapi itu pertanyaan Anda. Downvoting akan konyol ketika itu hanya ketidaksepakatan sederhana.
Mikel

Jawaban:

15

Awk (juga periksa Awk Info ) cantik dengan pertanyaan seperti itu. Mencoba:

awk -F'[],] *' '{print $2}' cities

Ini mendefinisikan pemisah bidang -Fsebagai [],] *- yang berarti satu kemunculan dari kurung siku penutup atau koma, diikuti oleh nol atau sejumlah spasi. Tentu saja Anda dapat mengubahnya agar sesuai dengan persyaratan apa pun. Baca dengan ekspresi reguler.

Setelah garis terpecah, Anda dapat melakukan apa yang Anda inginkan dengan hasil perpecahan. Di sini, saya memutuskan untuk mencetak kolom kedua hanya dengan print $2. Perhatikan bahwa penting untuk menggunakan tanda kutip tunggal di sekitar instruksi awk jika tidak $ 2 akan diganti oleh shell.

pindahkan
sumber
2
]bukan braket sudut. Kurung sudut adalah <>. []adalah "tanda kurung", atau hanya "tanda kurung".
cjm
Saya pikir Anda perlu melarikan diri dari kurung tutup itu, kecuali saya benar-benar perlu membaca tentang ekspresi reguler saya.
Kit Sunde
@cjm - Mungkin dia orang Jerman: news.ycombinator.com/item?id=1181243 :)
Kit Sunde
1
@ cjm, maaf saya bermaksud mengatakan kurung siku, mengetik agak terlalu cepat. @Kit, saya bukan orang Jerman. Anda tidak ingin keluar dari braket penutup bagian dalam (tidak ada gunanya), tetapi harus menjadi karakter pertama dalam rentang tersebut.
asoundmove
12

Anda dapat memodifikasi yang terakhir cutdalam saluran Anda untuk ini:

cut -d ' ' -f2-

Di atas berarti pemisah bidang adalah spasi, dan kami ingin memilih semua bidang mulai dari yang kedua. Urutan lengkap menjadi:

cut -d ',' -f1 cities | cut -d ' ' -f2-
Barun
sumber
12

Untuk penguraian yang lebih kompleks, Anda harus menggunakan sed (1) :

sed -e 's/\[[0-9]\+\] \([^,]\+\),.*/\1/' cities

Atau gunakan -runtuk menyederhanakan ekspresi reguler, seperti yang disarankan oleh pepoluan :

sed -re 's/\[[0-9]+\] ([^,]+),.*/\1/' cities
Juliano
sumber
2
+1. Anda juga dapat menggunakan -r untuk mencegah lolosnya karakter regex yang canggih, sangat menyederhanakan pola regex
pepoluan
0

Saya biasanya menggunakan Perl ketika semuanya menjadi terlalu sulit untuk sed dan grep.

Ada beberapa cara Anda bisa menulisnya di Perl. Misalnya, Anda mungkin lebih suka itu cepat, atau Anda mungkin lebih suka untuk menangani sedikit masalah yang tidak terduga dalam input (misalnya dua ruang di mana satu diharapkan).

Salah satu cara yang jelas (menganggap id adalah numerik, kota adalah alfabet, status adalah alfabet):

while (<>) {
    if (/^\[\d+\] (\w+(?: \w+)*), \w+ \(\w*\)$/) {
        my $city = $1;
        print "$city\n";
    }
}

Atau lebih lambat tetapi lebih permisif (melakukan lebih banyak backtracking):

while (<>) {
    if (/^.*\]\s+(.*),.*$/) {
        my $city = $1;
        print "$city\n";
    }
}

Atau lebih cepat (bidang berhenti saat kemunculan braket penutupan pertama):

while (<>) {
    if (/^\[[^]]*\] ([^,]*), \S+ \([^)]*\)$/) {
        my $city = $1;
        print "$city\n";
    }
}

Dari baris perintah daripada skrip, Anda bisa menggunakan -nopsi, yang pada dasarnya menambahkan while (<>) { BLOCK }loop:

perl -ne '/^\[[^]]*\] ([^,]*), \S+ \([^)]*\)$/ and print $1, "\n";' cities

atau jika Anda ingin penggunaannya menyerupai cut, Anda dapat menggunakan -Fopsi, yang mirip dengan -Fopsi awk , misalnya:

perl -a -n -F'/[],]\s+/' -e 'print $F[1], "\n"' cities

Cara ini jelas mengasumsikan bahwa tidak ada bidang yang akan mengandung pembatas.

Mikel
sumber