Як за допомогою команди оболонки відображати лише перший і останній стовпчик у текстовому файлі?


30

Мені потрібна допомога, щоб з’ясувати, як за допомогою команди sed показати лише перший і останній стовпчик у текстовому файлі. Ось що я поки що мав для колонки 1:

cat logfile | sed 's/\|/ /'|awk '{print $1}'

Моя слабка спроба отримати останній стовпець, щоб показати також:

cat logfile | sed 's/\|/ /'|awk '{print $1}{print $8}'

Однак це займає перший і останній стовпчик і об'єднує їх в один список. Чи є спосіб друкувати перший і останній стовпці чітко за допомогою команд sed і awk?

Зразок введення:

foo|dog|cat|mouse|lion|ox|tiger|bar

5
Будь ласка, надайте зразок.
Jasonwryan

Відповіді:


51

Майже там. Просто покладіть обидві посилання стовпців поруч.

cat logfile | sed 's/|/ /' | awk '{print $1, $8}'

Також зауважте, що вам тут не потрібно cat.

sed 's/|/ /' logfile | awk '{print $1, $8}'

Також зауважте, що ви можете сказати, awkщо роздільники стовпців є |замість пробілів, тому вам також не потрібно sed.

awk -F '|' '{print $1, $8}' logfile

Відповідно з пропозиціями по Калева , якщо ви хочете , рішення , яке до сих пір виводить останнє поле, навіть якщо не зовсім вісім, ви можете використовувати $NF.

awk -F '|' '{print $1, $NF}' logfile

Крім того, якщо ви хочете, щоб вихід зберігав |роздільники, замість того, щоб використовувати пробіл, ви можете вказати роздільники вивідних полів. На жаль, це трохи незграбніше, ніж просто використовувати -Fпрапор, але ось три підходи.

  • Ви можете призначити роздільники полів введення та виводу в awkсобі, в блоці BEGIN.

    awk 'BEGIN {FS = OFS = "|"} {print $1, $8}' logfile
  • Ви можете призначити ці змінні під час виклику awkз командного рядка через -vпрапор.

    awk -v 'FS=|' -v 'OFS=|' '{print $1, $8}' logfile
  • або просто:

    awk -F '|' '{print $1 "|" $8}' logfile

4
Хороша робота, що дозволяє спростити цю проблему. Ви можете додати примітку про те, як використовувати |як розділювач виводу замість місця за замовчуванням для об'єднання рядків. Також ви можете пояснити використання $NFзамість жорсткого кодування $8для отримання останнього стовпця.
Калеб

12

Просто замініть від першого до останнього |на |(або пробіл, якщо хочете):

sed 's/|.*|/|/'

Зауважте, що хоч немає жодної sedреалізації, де |є особливим (доки розширені регулярні вирази не ввімкнуті через -Eабо -rв деяких реалізаціях), \|сам по собі є спеціальним у деяких, як GNU sed. Тож вам не слід бігти, |якщо ви маєте намір відповідати |персонажу.

Якщо ви замінюєте пробіл і якщо вхідні дані вже можуть містити рядки лише з одним |, тоді вам доведеться трактувати це спеціально як таке |.*|, що не відповідає цим. Це може бути:

sed 's/|\(.*|\)\{0,1\}/ /'

(тобто зробити .*|деталь необов’язковою) Або:

sed 's/|.*|/ /;s/|/ /'

або:

sed 's/\([^|]*\).*|/\1 /'

Якщо ви хочете перше і восьме поля незалежно від кількості полів на вході, це просто:

cut -d'|' -f1,8


(всі вони будуть працювати з будь-якою утилітою, сумісною з POSIX, припускаючи, що для вхідних текстів є дійсним текст (зокрема, sedті, як правило, не працюватимуть, якщо вхід має байти чи послідовності байтів, які не утворюють дійсних символів у поточному мові, наприклад, printf 'unix|St\351phane|Chazelas\n' | sed 's/|.*|/|/'у локалітет UTF-8)).


11

Ви все awkодно використовуєте :

awk '{ print $1, $NF }' file

2
Чи не потрібно буде вказувати роздільник поля введення (оскільки в цьому випадку це здається |, що це просто пробіл) з -F\|або подібним? А що робити, якщо він хотів використовувати той самий роздільник для виведення?
Калеб

@Caleb Напевно: я чекав, коли ОП підтвердить, як саме виглядав вхід, а не намагався вгадати на основі непрацюючих прикладів ...
jasonwryan

1
Зауважте, що цей припущення містить щонайменше 2 поля.
Стефан Шазелас

@ StéphaneChazelas OP чітко зазначив, що в коді завжди є вісім полів.
michaelb958

3
@ michaelb958 Я думаю, що "явно" перебільшує справу, лише трохи :)
jasonwryan

4

Якщо ви виявите себе незручнішими і без сед, ви можете домогтися того ж з Coreutils:

paste <(           cut -d'|' -f1  file) \ 
      <(rev file | cut -d'|' -f1 | rev)

cutє більш чистим і компактним, ніж awk / sed, коли вас просто цікавить перший стовпець або якщо деліметри фіксовані (тобто не змінна кількість пробілів).
Шрідхар Сарнобат

2

Схоже, ви намагаєтеся отримати перше і останнє поля тексту, які розмежовані |.

Я припускаю, що ваш файл журналу містить текст, як показано нижче,

foo|dog|cat|mouse|lion|ox|tiger|bar
bar|dog|cat|mouse|lion|ox|tiger|foo

І ви хочете, як результат,

foo bar
bar foo

Якщо так, то тут приходить команда для ваших

Через GNU sed,

sed -r 's~^([^|]*).*\|(.*)$~\1 \2~' file

Приклад:

$ echo 'foo|dog|cat|mouse|lion|ox|tiger|bar' | sed -r 's~^([^|]*).*\|(.*)$~\1 \2~'
foo bar

Стовпці не розмежовані трубою | але вони знаходяться в стовпцях, мені цікаво використовувати sed, але не використовувати команду awk, як ви це робили у вашій команді: sed -r 's ~ ^ ([^ |] *). * \ | (. *) $ ~ \ Файл 1 \ 2 ~ '
user70573

"Стовпці не обмежені трубою |, але вони є стовпцями", ви маєте на увазі колонки розділені пробілами?
Авінаш Радж

Зразок введення та вихід був би кращим.
Avinash Raj

1

Вам, мабуть, варто зробити це з sed- я б все одно, але тільки тому, що ще ніхто не написав цього:

while IFS=\| read col1 cols
do  printf %10s%-s\\n "$col1 |" " ${cols##*|}"
done <<\INPUT
foo|dog|cat|mouse|lion|ox|tiger|bar
INPUT

ВИХІД

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