@Jefromi - тоже cutне имеет регулярных выражений перед {}действиями, да и то тупее с разделителями полей (переменное количество пробелов?), И их приходится указывать вручную. Я думаю, ОП хотел услышать о какой-то shift Nкоманде, которой не существует. Самый близкий $1="";$2="";(...);print}, но в моем случае он оставляет некоторые ведущие пробелы (возможно, разделители).
Tomasz Gandor
Ответы:
50
Решение, которое не добавляет лишних начальных или конечных пробелов :
Ответ ЭдМортона не сработал для меня (bash 4.1.2 (1) -release, GNU Awk 3.1.7 или bash 3.2.25 (1) -release, GNU Awk 3.1.5), но нашел здесь другой способ:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch
1
@elysch нет, это не будет работать в целом, это просто работает с некоторыми конкретными входными значениями. См. Комментарий, который я добавил под вашим комментарием под моим ответом.
Эд Мортон
1
Привет @fedorqui. Мой ответ первый. В моем первоначальном ответе я объяснял, почему другой ответ был неправильным (лишние начальные или конечные пробелы). Некоторые люди предлагали улучшения в комментариях. Мы попросили ОП выбрать более правильный ответ, и он выбрал мой. После того, как некоторые другие участники отредактировали мой ответ, чтобы сослаться на ответ (см. Историю). Вам это понятно? Что вы посоветуете мне, чтобы мой ответ был понятнее? Cheers ;-)
olibre
1
Вы абсолютно правы, и я очень сожалею о своем недоразумении. Я быстро прочитал ответ и не заметил вашего исходного ответа (да, я прочитал слишком быстро). +1 для самого ответа, используя красивый трюк, чтобы перейти к NF-1 и затем распечатать последний элемент, чтобы избежать лишних пробелов. И еще раз извините! (удаляю свой комментарий через день или около того, чтобы предотвратить недопонимание со стороны будущих читателей).
fedorqui 'SO, перестань причинять вред'
1
Я бы использовал какие-то заголовки: <ваш ответ>, а затем горизонтальное правило, за которым следует большой заголовок «Сравнение других ответов». В противном случае переместите это сравнение к другому ответу, поскольку, очевидно, люди предпочитают короткие ответы в видении «дай мне мой код»
вероятно, лучше использовать «NF», чем «13» в последнем примере.
Гленн Джекман
2
2 сценария, который должен решить OP. если 13 - последнее поле, можно использовать NF. Если нет, то уместно использовать 13.
ghostdog74
3
2-й должен удалить 3 копии OFS с начала 0 $. 3-й будет лучше с printf "%s ",$i, так как вы не знаете, $iможет ли он содержать %sили что-то подобное. Но это напечатало бы лишний пробел в конце.
Это приятно тем, насколько динамично. Вы можете добавлять столбцы в конце и не переписывать свои скрипты.
MinceMan
1
Это демонстрирует точную проблему, которую пытается решить вопрос, просто сделайте наоборот. А как насчет того, чтобы напечатать с сотого поля? Обратите внимание на то, что вы не имеете дела, NFпоэтому вы уходите в лидеры OFS.
Крис Сеймур
24
Правильный способ сделать это - использовать интервал RE, потому что он позволяет вам просто указать, сколько полей нужно пропустить, и сохраняет интервалы между полями для остальных полей.
например, пропустить первые 3 поля, не влияя на интервал между оставшимися полями, учитывая формат ввода, который мы, кажется, обсуждаем в этом вопросе, просто:
Если у вас есть FS, который является RE, который вы не можете отрицать в наборе символов, вы можете сначала преобразовать его в один символ (RS идеально подходит, если это один символ, поскольку RS НЕ МОЖЕТ появляться в поле, в противном случае рассмотрите SUBSEP), затем примените замену интервала RE, затем преобразуйте в OFS. например, если цепочки "." разделяют поля:
Тогда у вас будет та же проблема, что и со всеми решениями на основе цикла, которые переназначают поля - FS преобразуются в OFS. Если это проблема, вам нужно изучить функцию patsplit () GNU awks.
У меня не сработало (bash 4.1.2 (1) -release, GNU Awk 3.1.7 или bash 3.2.25 (1) -release, GNU Awk 3.1.5), но нашел здесь другой способ:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch
2
Нет, это не сработает, если $ 1 или $ 2 содержат строку, установленную для $ 3. Попробуйте, например, echo ' That is a test' | awk '{print substr($0, index($0,$3))}'и вы обнаружите, aчто сумма в 3 доллара совпадает с aвнутренней частью Thatв 1 доллар. В очень старой версии gawk, такой как у вас, вам нужно включить интервалы RE с помощью флага --re-interval.
Эд Мортон
2
Вы правы, не заметили. Кстати, очень признателен за ваш комментарий. Много раз хотел использовать регулярное выражение с "{}" для указания количества элементов и никогда не видел "--re-interval" в человеке. +1 для вас.
elysch
1
1является истинным условием и поэтому вызывает действие awk по умолчанию для печати текущей записи.
Эд Мортон
1
Не знаю, насколько это канонично, но я добавил ответ сейчас.
Эд Мортон
10
Практически все ответы в настоящее время добавляют либо ведущие пробелы, либо конечные пробелы, либо некоторые другие проблемы с разделителями. Чтобы выбрать из четвертого поля, где разделитель - это пробел, а выходной разделитель - это один пробел, используйте следующее awk:
Или, чтобы разместить их в той же строке, назначьте 3 доллара на 1 и т. Д., А затем измените NF на нужное количество полей. echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
larsr
Привет @larsr. Предлагаемая вами командная строка - единственный правильный ответ. Все остальные ответы добавляют дополнительные пробелы (ведущие или конечные). Пожалуйста, опубликуйте свою командную строку в новом ответе, я проголосую за нее ;-)
olibre
1
Привет, @sudo_O, я говорил с @larsr о командной строке, которую он предложил в своем комментарии. Я потратил около пяти минут, прежде чем выяснить quiproco (недоразумение). Я согласен, ответ @Vetsin вставляет новые строки ( ORS) между полями. Браво за вашу инициативу (мне нравится ваш ответ). Cheers
olibre
3
Другой способ избежать использования оператора печати:
$ awk '{$1=$2=$3=""}sub("^"FS"*","")' file
В awk, когда условие истинно, печать является действием по умолчанию.
+1 за аналогичное решение ... Но это может иметь проблемы с производительностью, если fileоно велико (> 10-30 КБ). Для больших файлов awkрешение работает лучше.
TrueY
3
Варианты с 1 по 3 имеют проблемы с несколькими пробелами (но они просты). Это причина для разработки вариантов 4 и 5, которые без проблем обрабатывают несколько пробелов. Конечно, если варианты 4 или 5 используются с n=0обоими, все начальные пробелы сохранятся, что n=0означает отсутствие разделения.
Опция 1
Простое решение для разрезания (работает с одиночными разделителями):
$ echo '1 2 3 4 5 6 7 8'| cut -d' '-f4-45678
Вариант 2
Принудительное повторное вычисление awk иногда решает проблему (работает с некоторыми версиями awk) с добавленными ведущими пробелами:
ПРИМЕЧАНИЕ: «^ [« FS »] *» означает ввод с ведущими пробелами.
Вариант 5
Вполне возможно построить решение, которое не добавит лишних начальных или конечных пробелов и сохранит существующие пробелы, используя функцию gensubиз GNU awk, например:
Привет БЖ Ваш ответ приятный. Но вариант 3 не работает со строкой, начинающейся с пробела (например " 1 2 3 4 5 6 7 8 "). Вариант 4 хорош, но оставьте начальный пробел, используя строку, начинающуюся с пробела. Как вы думаете, поправимо ли это? Вы можете использовать команду echo " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'для проверки
начальных
Привет @olibre. То, что вариант 3 не работает с пробелом, является причиной разработки вариантов 4 и 5. Вариант 4 оставляет начальный пробел только в том случае, если он есть во входных данных и n установлено в 0 (n = 0). Я считаю, что это правильный ответ, когда нет выбора полей (ничего, чтобы исправить IMO). Приветствия.
Отлично. Спасибо за дополнительную информацию :-) Пожалуйста, улучшите свой ответ,
добавив
Отлично :-) Как жаль, что ваш пользователь отключен :-(
olibre
1
Cut имеет флаг --complement, который упрощает (и ускоряет) удаление столбцов. Полученный синтаксис аналогичен тому, что вы хотите сделать, - это упрощает чтение / понимание решения. Дополнение также работает для случая, когда вы хотите удалить несмежные столбцы.
Помогает ли приведенное выше редактирование в понимании? Дело в том, чтобы использовать флаг дополнения cut. Решение должно быть более быстрой и лаконичной, чем решения на основе AWK или Perl. Также можно вырезать произвольные столбцы.
Майкл Бэк
1
Решение Perl, которое не добавляет начальные и конечные пробелы:
Поскольку меня раздражал первый, получивший большое количество голосов, но неправильный ответ, я нашел достаточно, чтобы написать там ответ, а здесь неправильные ответы отмечены как таковые, вот и мой бит. Мне не нравятся предлагаемые решения, потому что я не вижу причин давать такой сложный ответ.
У меня есть журнал, в котором после 5 долларов с IP-адресом может быть больше текста или нет текста. Мне нужно все, от IP-адреса до конца строки, если что-то стоит после 5 долларов. В моем случае это действительно с awk-программой, а не с одной строкой awk, поэтому awk должен решить проблему. Когда я пытаюсь удалить первые 4 поля, используя старый красивый и получивший наибольшее количество голосов, но совершенно неправильный ответ:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three"| awk '{$1=$2=$3=$4=""; printf "[%s]\n", $0}'
он выдает неправильный и бесполезный ответ (я добавил [] для демонстрации):
[37.244.182.218 one two three]
Вместо этого, если столбцы имеют фиксированную ширину до тех пор, пока не потребуется точка отсечения и awk, правильный и довольно простой ответ:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three"| awk '{printf "[%s]\n", substr($0,28)}'
В %-5sсовмещается результат как 5-символьный широкими колонны; если этого недостаточно, увеличьте число или используйте %s(с пробелом) вместо этого, если вас не волнует выравнивание.
Решение на основе AWK printf, которое позволяет избежать проблемы с% и уникально тем, что ничего не возвращает (без символа возврата), если для печати осталось менее 4 столбцов:
cut -f3-
?cut
не имеет регулярных выражений перед{}
действиями, да и то тупее с разделителями полей (переменное количество пробелов?), И их приходится указывать вручную. Я думаю, ОП хотел услышать о какой-тоshift N
команде, которой не существует. Самый близкий$1="";$2="";(...);print}
, но в моем случае он оставляет некоторые ведущие пробелы (возможно, разделители).Ответы:
Решение, которое не добавляет лишних начальных или конечных пробелов :
Sudo_O предлагает элегантное улучшение с использованием тернарного оператора
NF?ORS:OFS
EdMorton предлагает решение, сохраняющее исходные пробелы между полями:
BinaryZebra также предоставляет два потрясающих решения:
(эти решения даже сохраняют конечные пробелы из исходной строки)
Решение, данное larsr в комментариях, почти правильное:
Это фиксированная и параметризованная версия решения larsr :
Все остальные ответы до сентября 2013 года хороши, но добавляют лишние пробелы:
Пример ответа с добавлением лишних ведущих пробелов :
Пример ответа с добавлением лишнего конечного пробела
источник
echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
источник
OFS
поскольку вы не имеете дело сNF
пробелом в записях.использовать разрез
или если вы настаиваете на awk и $ 13 - последнее поле
еще
источник
printf "%s ",$i
, так как вы не знаете,$i
может ли он содержать%s
или что-то подобное. Но это напечатало бы лишний пробел в конце.Попробуй это:
источник
NF
поэтому вы уходите в лидерыOFS
.Правильный способ сделать это - использовать интервал RE, потому что он позволяет вам просто указать, сколько полей нужно пропустить, и сохраняет интервалы между полями для остальных полей.
например, пропустить первые 3 поля, не влияя на интервал между оставшимися полями, учитывая формат ввода, который мы, кажется, обсуждаем в этом вопросе, просто:
Если вы хотите разместить ведущие пробелы и непустые пробелы, но снова с FS по умолчанию, тогда это:
Если у вас есть FS, который является RE, который вы не можете отрицать в наборе символов, вы можете сначала преобразовать его в один символ (RS идеально подходит, если это один символ, поскольку RS НЕ МОЖЕТ появляться в поле, в противном случае рассмотрите SUBSEP), затем примените замену интервала RE, затем преобразуйте в OFS. например, если цепочки "." разделяют поля:
Очевидно, что если OFS - это один символ и он не может отображаться в полях ввода, вы можете уменьшить его до:
Тогда у вас будет та же проблема, что и со всеми решениями на основе цикла, которые переназначают поля - FS преобразуются в OFS. Если это проблема, вам нужно изучить функцию patsplit () GNU awks.
источник
echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
echo ' That is a test' | awk '{print substr($0, index($0,$3))}'
и вы обнаружите,a
что сумма в 3 доллара совпадает сa
внутренней частьюThat
в 1 доллар. В очень старой версии gawk, такой как у вас, вам нужно включить интервалы RE с помощью флага--re-interval
.1
является истинным условием и поэтому вызывает действие awk по умолчанию для печати текущей записи.Практически все ответы в настоящее время добавляют либо ведущие пробелы, либо конечные пробелы, либо некоторые другие проблемы с разделителями. Чтобы выбрать из четвертого поля, где разделитель - это пробел, а выходной разделитель - это один пробел, используйте следующее
awk
:Чтобы параметризовать начальное поле, вы можете:
А также конечное поле:
источник
Ввод
Вывод
источник
источник
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
ORS
) между полями. Браво за вашу инициативу (мне нравится ваш ответ). CheersДругой способ избежать использования оператора печати:
В awk, когда условие истинно, печать является действием по умолчанию.
источник
awk '{$1=$2=$3=""}sub("^"OFS"+","")' file
как и OFS, что осталось после изменения содержимого $ 1, $ 2 и $ 3.Не могу поверить, что никто не предлагал простую оболочку:
источник
file
оно велико (> 10-30 КБ). Для больших файловawk
решение работает лучше.Варианты с 1 по 3 имеют проблемы с несколькими пробелами (но они просты). Это причина для разработки вариантов 4 и 5, которые без проблем обрабатывают несколько пробелов. Конечно, если варианты 4 или 5 используются с
n=0
обоими, все начальные пробелы сохранятся, чтоn=0
означает отсутствие разделения.Опция 1
Простое решение для разрезания (работает с одиночными разделителями):
Вариант 2
Принудительное повторное вычисление awk иногда решает проблему (работает с некоторыми версиями awk) с добавленными ведущими пробелами:
Вариант 3
Печать каждого поля, сформированного с помощью
printf
, даст больше контроля:Однако все предыдущие ответы меняют все FS между полями на OFS. Давайте создадим для этого пару решений.
Вариант 4
Цикл с подпрограммой для удаления полей и разделителей более переносим и не вызывает изменения FS на OFS:
ПРИМЕЧАНИЕ: «^ [« FS »] *» означает ввод с ведущими пробелами.
Вариант 5
Вполне возможно построить решение, которое не добавит лишних начальных или конечных пробелов и сохранит существующие пробелы, используя функцию
gensub
из GNU awk, например:Его также можно использовать для замены списка полей с учетом количества
n
:Конечно, в таком случае OFS используется для разделения обеих частей строки, а конечный пробел полей все еще печатается.
Примечание1:
["FS"]*
используется для разрешения ведущих пробелов в строке ввода.источник
" 1 2 3 4 5 6 7 8 "
). Вариант 4 хорош, но оставьте начальный пробел, используя строку, начинающуюся с пробела. Как вы думаете, поправимо ли это? Вы можете использовать командуecho " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
для проверкиCut имеет флаг --complement, который упрощает (и ускоряет) удаление столбцов. Полученный синтаксис аналогичен тому, что вы хотите сделать, - это упрощает чтение / понимание решения. Дополнение также работает для случая, когда вы хотите удалить несмежные столбцы.
источник
Решение Perl, которое не добавляет начальные и конечные пробелы:
@F
Массив perl autosplit начинается с индекса,0
а поля awk начинаются с$1
Решение Perl для данных, разделенных запятыми:
Решение Python:
python -c "import sys;[sys.stdout.write(' '.join(line.split()[3:]) + '\n') for line in sys.stdin]" < file
источник
Для меня наиболее компактным и совместимым решением запроса является
И если вам нужно обработать больше строк, например, файл foo.txt , не забудьте сбросить i до 0:
Спасибо вашему форуму.
источник
Поскольку меня раздражал первый, получивший большое количество голосов, но неправильный ответ, я нашел достаточно, чтобы написать там ответ, а здесь неправильные ответы отмечены как таковые, вот и мой бит. Мне не нравятся предлагаемые решения, потому что я не вижу причин давать такой сложный ответ.
У меня есть журнал, в котором после 5 долларов с IP-адресом может быть больше текста или нет текста. Мне нужно все, от IP-адреса до конца строки, если что-то стоит после 5 долларов. В моем случае это действительно с awk-программой, а не с одной строкой awk, поэтому awk должен решить проблему. Когда я пытаюсь удалить первые 4 поля, используя старый красивый и получивший наибольшее количество голосов, но совершенно неправильный ответ:
он выдает неправильный и бесполезный ответ (я добавил [] для демонстрации):
Вместо этого, если столбцы имеют фиксированную ширину до тех пор, пока не потребуется точка отсечения и awk, правильный и довольно простой ответ:
который дает желаемый результат:
источник
Я нашел эту возможность, может быть, она тоже может быть полезна ...
awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file
Примечание. 1. Для табличных данных и столбцов от 1 до 14 долларов.
источник
Используйте разрез:
например: Если у вас есть
file1
:car.is.nice.equal.bmw
Выполнить:
cut -d . -f1,3 file1
напечатаетcar.is.nice
источник
Это не очень далеко от некоторых из предыдущих ответов, но решает несколько проблем:
cols.sh
:Который теперь можно вызвать с аргументом, который будет начальным столбцом:
Или:
Это 1-индексированный; если вы предпочитаете нулевая индексация, используйте
i=s + 1
вместо этого.Более того, если вы хотите иметь аргументы для начального индекса и конечного индекса, измените файл на:
Например:
В
%-5s
совмещается результат как 5-символьный широкими колонны; если этого недостаточно, увеличьте число или используйте%s
(с пробелом) вместо этого, если вас не волнует выравнивание.источник
Решение на основе AWK printf, которое позволяет избежать проблемы с% и уникально тем, что ничего не возвращает (без символа возврата), если для печати осталось менее 4 столбцов:
Тестирование:
источник