Как использовать команду оболочки, чтобы показать только первый столбец и последний столбец в текстовом файле?

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
user70573
источник
5
Пожалуйста, предоставьте образец ввода.
Джейсонвриан

Ответы:

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
Sparhawk
источник
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
jasonwryan
источник
2
Разве вам не нужно указывать разделитель поля ввода (поскольку в данном случае это |скорее пробел) с -F\|или аналогично? И что если он захочет использовать тот же разделитель для вывода?
Калеб
@Caleb Вероятно: я ждал, чтобы ОП подтвердил, как именно выглядел ввод, а не пытался угадать, основываясь на нерабочих примерах ...
jasonwryan
1
Обратите внимание, что предполагается, что вход содержит как минимум 2 поля.
Стефан Шазелас
@ StéphaneChazelas OP четко указал в коде, что у него всегда восемь полей.
michaelb958 - Восстановить Монику
3
@ michaelb958 Я думаю, что "ясно" преувеличивает дело, только немного :)
jasonwryan
4

Если вы обнаружите, что вам не хватает awk и sed, вы можете добиться того же с помощью 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 ~ 'file
user70573
«Столбцы не разделены конвейером | но они находятся в столбцах», вы имеете в виду, что столбцы разделены пробелами?
Авинаш Радж
Пример ввода и вывода будет лучше.
Авинаш Радж
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
mikeserv
источник