Що я повинен використовувати, коли розріз не ріже його?


19

У мене такий файл cities:

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

Я хочу вирізати назви міст, щоб мати:

San Diego
St Louis
Orlando

Це найкраще, що я міг придумати:

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

Але це все ще залишає мені пробіл перед іменами. Чи є cutподібна команда, яку я можу використовувати, щоб прийняти роздільники кількох символів, щоб я міг вирізати ]?


1
trкорисно для видалення символів, які ви не хочете.
ЛоуренсC

Якщо ви спробуєте код у відповідях людей, ви побачите три різні виходи. Це говорить про те, що ваше запитання не було на 100% зрозумілим. Чи означає «вирізати» видалення чи вибір? Хочете ви (inactive)статус чи ні? Будь ласка, надайте зразок виводу.
Мікель

@Mikel - Зважаючи на те, що я використовую cutдля вирізання речей, і ви бачите наміри невдалого прикладу, який я маю, він повинен бути досить чітким у контексті. Я надам зразок, хоча для подальшого очищення. :)
Kit Sunde

Ні, не дуже. Я змінив одне речення у вашому запитанні, щоб "надрукувати лише назви міст", тому що саме ваше використання слова "вирізати" було для мене незрозумілим. Чи правильна моя зміна?
Мікель

1
@Kit Sunde: З результатом вибірки це, безумовно, зрозуміло. Назва мила. "вирізати" змушує задуматися про те, що відбувається, коли ви натискаєте Ctrl + X, саме тому я запропонував зміни, але це ваше питання. Відхилення зусиль було б нерозумним, коли це просто проста незгода.
Мікель

Відповіді:


15

Awk (також перевірити Awk Info ) прекрасний з таким питанням. Спробуйте:

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

Це визначає роздільник поля -Fяк [],] *- що означає виникнення або закриваючого квадратного дужки, або коми, з наступним нулем або будь-якою кількістю пробілів. Звичайно, ви можете змінити це відповідно до будь-яких вимог. Читайте на регулярних виразах.

Після того, як лінія розбита, ви можете робити все, що завгодно, з результатом розділення. Тут я вирішив роздрукувати друге поле лише за допомогою print $2. Зауважте, що важливо використовувати одиничні котирування навколо інструкцій awk, інакше $ 2 буде замінено оболонкою.


2
]не є кутовою дужкою. Кутові дужки є <>. []є "квадратними дужками", або просто "дужками".
cjm

Я думаю, що вам потрібно уникнути цієї замикаючої дужки, якщо мені насправді не потрібно читати свої регулярні вирази.
Kit Sunde

@cjm - Можливо, він німецький: news.ycombinator.com/item?id=1181243 :)
Kit Sunde

1
@cjm, вибач, що я мав на увазі сказати квадратну дужку, надруковану трохи занадто швидко. @Kit, я не німець. Ви не хочете уникати внутрішньої дужки закриття (це не послужило б меті), але це повинен бути першим символом у діапазоні.
asoundmove

12

Ви можете змінити останній cutу своєму трубопроводі до цього:

cut -d ' ' -f2-

Вище сказане означає, що роздільник поля є пробілом, і ми хочемо вибрати всі поля, починаючи з другого. Повна послідовність стає:

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

12

Для більш складного розбору слід використовувати sed (1) :

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

Або використовуючи -rдля спрощення регулярного вираження, як це запропонував pepoluan :

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

2
+1. ви також можете використовувати -r для запобігання уникненню розширених символів регулярних
виразів

0

Я зазвичай використовую Perl, коли все стає занадто важким для sed і grep.

Існує декілька способів, як ви могли це написати в Perl. Наприклад, ви можете віддати перевагу тому, що він буде швидким, або ви можете вирішити невеликі несподівані проблеми у введенні (наприклад, два пробіли, де очікувалося одне).

Один очевидний спосіб (припускає, що ідентифікатор числовий, місто - алфавітне, статус - за алфавітом):

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

Або повільніше, але більш дозволено (робить більше зворотних треків):

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

Або швидше (поле зупиняється при першому появі закриваючої дужки):

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

З командного рядка, а не сценарію, ви можете використовувати -nпараметр, який в основному додає while (<>) { BLOCK }цикл:

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

або якщо ви хочете, щоб використання нагадувало розріз, ви можете використовувати -Fпараметр, подібний до -Fпараметра awk , наприклад:

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

Таким чином, очевидно, передбачається, що жодне поле не буде містити жодного роздільника.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.