как удалить первые два столбца в файле с помощью оболочки (awk, sed, что угодно)

52

У меня есть файл со многими строками в каждой строке есть много столбцов (полей), разделенных пробелом "" количество столбцов в каждой строке различно Я хочу удалить первые два столбца как?

Теги:
awk
sed
cut

10 ответов

126

Вы можете сделать это с помощью cut:

cut -d " " -f 3- input_filename > output_filename

Объяснение:

  • cut: вызвать команду cut
  • -d " ": в качестве разделителя используйте единое пространство (cut использует TAB по умолчанию)
  • -f: укажите поля для сохранения
  • 3-: все поля, начинающиеся с поля 3
  • input_filename: используйте этот файл как вход
  • > output_filename: напишите вывод в этот файл.

В качестве альтернативы вы можете сделать это с помощью awk:

awk '{$1=""; $2=""; sub("  ", " "); print}' input_filename > output_filename

Объяснение:

  • awk: вызывать команду awk
  • $1=""; $2="";: установите поле 1 и 2 в пустую строку
  • sub(...);: очистить выходные поля, потому что поля 1 и 2 все равно будут разделены символом ""
  • print: напечатать измененную строку
  • input_filename > output_filename: то же, что и выше.
  • 1
    вторая работает, первая не работает, спасибо
  • 0
    @wenzi Упс, забыл, что по умолчанию cut использует табуляцию в качестве разделителя. Смотрите обновленный ответ - только что проверил и все работает. при прочих равных я бы порекомендовал использовать cut over awk .
Показать ещё 2 комментария
17

Вот один из способов сделать это с Awk, который относительно легко понять:

awk '{print substr($0, index($0, $3))}'

Это простая команда awk без шаблона, поэтому действие внутри {} выполняется для каждой строки ввода.

Действие состоит в том, чтобы просто напечатать подстроку, начиная с позиции третьего поля.

  • $0: вся строка ввода
  • $3: 3-е поле
  • index(in, find): возвращает позицию find в строке in
  • substr(string, start): вернуть подстроку, начинающуюся с индекса start

Если вы хотите использовать другой разделитель, например запятую, вы можете указать его с опцией -F:

awk -F"," '{print substr($0, index($0, $3))}'

Вы также можете использовать это в подмножестве входных строк, указав шаблон перед действием в {}. Только строки, соответствующие шаблону, будут выполняться.

awk 'pattern{print substr($0, index($0, $3))}'

Где шаблон может быть таким, как:

  • /abcdef/: использовать регулярное выражение, по умолчанию работает по $0.
  • $1 ~ /abcdef/: работайте в определенном поле.
  • $1 == blabla: используйте сравнение строк
  • NR > 1: использовать запись/номер строки
  • NF > 0: использовать поле/номер столбца
  • 1
    Спасибо за это, это более хороший ответ, чем принятый IMO
  • 0
    Как насчет удаления последних 2 столбцов, считая с обратного?
Показать ещё 1 комментарий
9

Спасибо за сообщение вопроса. Я также хотел бы добавить script, который помог мне.

awk '{ $1=""; print $0 }' file
  • 1
    В этом случае Awk не сохраняет разделители полей.
8
awk '{$1=$2="";$0=$0;$1=$1}1'

Ввод

a b c d

Выход

c d
  • 0
    не могли бы вы объяснить? :) я не понимаю, зачем нужны $0=$0;$1=$1 для исчезновения пробелов
6

Довольно просто сделать это только с оболочкой

while read A B C; do
echo "$C"
done < oldfile >newfile
  • 0
    Это отличный ответ, однако вы захотите использовать read -r вместо read .
  • 0
    read -r сохранит обратную косую черту. read не буду. Например: echo "foo ba\r" выдаст вывод foo ba\r . Тем не менее, echo "foo ba\r" | (while read first_column second_column; do echo "$second_column"; done) будет выводить только bar в качестве вывода (с удаленной обратной косой чертой. Добавление флага -r приводит к правильному выводу ba\r
6

Вы можете использовать sed:

sed 's/^[^ ][^ ]* [^ ][^ ]* //'

Это ищет строки, начинающиеся с одного или более не-пробелов, пробела, другого набора из одного или нескольких незабитых и еще одного пустого и удаляет сопоставленный материал, например первые два поля. [^ ][^ ]* немного короче эквивалентной, но более явной нотации [^ ]\{1,\}, а вторая может столкнуться с проблемами с GNU sed (хотя, если вы используете --posix в качестве опции, даже GNU sed не может нафиг это). OTOH, если класс символов, который должен быть повторен, был более сложным, числовая нотация выигрывает для краткости. Его легко расширить, чтобы обрабатывать "пустую или табуляцию" как разделитель, или "множественные пробелы" или "множественные пробелы или вкладки". Он также может быть изменен для обработки необязательных заготовок (или вкладок) перед первым полем и т.д.

Для awk и cut см. Sampson-Chen ответ. Существуют и другие способы записи awk script, но они не намного лучше, чем ответ. Обратите внимание, что вам может потребоваться явно задать разделитель полей (-F" ") в awk, если вы не хотите, чтобы вкладки обрабатывались как разделители или у вас могло быть несколько пробелов между полями. Стандарт POSIX cut не поддерживает множественные разделители между полями; GNU cut имеет полезную, но нестандартную опцию -i, позволяющую использовать несколько разделителей между полями.

Вы также можете сделать это в чистой оболочке:

while read junk1 junk2 residue
do echo "$residue"
done < in-file > out-file
  • 0
    Если residue может содержать обратную косую черту, приведенное выше чтение будет интерпретировать его, а не воспроизводить его в выходных данных. Всегда используйте, while IFS= read -r ...
  • 0
    Если bash интерпретирует содержимое с простым read , то bash работает (снова). Команда чтения в оригинальных оболочках не делала такой ерунды; Я не верю, что это требуется оболочкой POSIX. Меня раздражало бы, что bash делает то, что вы говорите, - у меня уже есть отношения любовь / ненависть с программой, поскольку она делает много вещей хорошо, но есть некоторые вещи, которые она делает плохо, и изменение устаревшего поведения является одним из худших, и требование опции для включения старого стандартного поведения ... очень раздражает. Кажется, ты прав; bash завален!
Показать ещё 3 комментария
4

Perl:

perl -lane 'print join(' ',@F[2..$#F])' File

AWK:

awk '{$1=$2=""}1' File
1

Это может сработать для вас (GNU sed):

sed -r 's/^([^ ]+ ){2}//' file

или для столбцов, разделенных одним или несколькими пробелами:

sed -r 's/^(\S+\s+){2}//' file
0

Используя awk и, основываясь на некоторых из приведенных ниже опций, использование цикла for делает немного более гибким; иногда я могу удалить первые 9 столбцов (например, я делаю "ls -lrt" ), поэтому я меняю 2 на 9 и что он:

awk '{ for(i=0;i++<2;){$i=""}; print $0 }' your_file.txt

0

Используйте kscript

kscript 'lines.split().select(-1,-2).print()' file

Ещё вопросы

Сообщество Overcoder
Наверх
Меню