17 ответов:
решение, которое не добавляет дополнительные ведущие или конечные пробел:
awk '{ for(i=4; i<NF; i++) printf "%s",$i OFS; if(NF) printf "%s",$NF; printf ORS}' ### Example ### $ echo '1 2 3 4 5 6 7' | awk '{for(i=4;i<NF;i++)printf"%s",$i OFS;if(NF)printf"%s",$NF;printf ORS}' | tr ' ' '-' 4-5-6-7Sudo_O предлагает элегантное улучшение с помощью тернарного оператора
NF?ORS:OFS$ echo '1 2 3 4 5 6 7' | awk '{ for(i=4; i<=NF; i++) printf "%s",$i (i==NF?ORS:OFS) }' | tr ' ' '-' 4-5-6-7EdMorton дает решение, сохраняющее исходные пробелы между полями:
$ echo '1 2 3 4 5 6 7' | awk '{ sub(/([^ ]+ +){3}/,"") }1' | tr ' ' '-' 4---5----6-7BinaryZebra также предоставляет два удивительных решения:
(эти решения даже сохранить конечные пробелы из исходной строки)$ echo -e ' 1 2\t \t3 4 5 6 7 \t 8\t ' | awk -v n=3 '{ for ( i=1; i<=n; i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",);} } 1 ' | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/' "4...5...6.7.->.8->." $ echo -e ' 1 2\t \t3 4 5 6 7 \t 8\t ' | awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }' | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/' "4...5...6.7.->.8->."решение дано larsr в комментариях почти правильно:
$ echo '1 2 3 4 5 6 7' | awk '{for (i=3;i<=NF;i++) $(i-2)=$i; NF=NF-2; print }' | tr ' ' '-' 3-4-5-6-7это фиксированная и параметризованная версия larsr устранение:
$ echo '1 2 3 4 5 6 7' | awk '{for(i=n;i<=NF;i++)$(i-(n-1))=$i;NF=NF-(n-1);print }' n=4 | tr ' ' '-' 4-5-6-7все остальные ответы до сентября-2013 хороши, но добавьте дополнительные пробелы:
пример ответ добавление дополнительных ведущих пробелы:
$ echo '1 2 3 4 5 6 7' | awk '{===""}1' | tr ' ' '-' ---4-5-6-7пример ответ, добавив лишний пробел
$ echo '1 2 3 4 5 6 7' | awk '{for(i=4;i<=13;i++)printf "%s ",$i;printf "\n"}' | tr ' ' '-' 4-5-6-7-------
использовать cut
$ cut -f4-13 fileили если вы настаиваете на awk и 13 $ - это последнее поле
$ awk '{==="";print}' fileдругое
$ awk '{for(i=4;i<=13;i++)printf "%s ",$i;printf "\n"}' file
правильный способ сделать это-с интервалом RE, потому что он позволяет вам просто указать, сколько полей пропустить, и сохраняет межпольное расстояние для остальных полей.
например, чтобы пропустить первые 3 поля, не влияя на расстояние между остальными полями, учитывая формат ввода, который мы, кажется, обсуждаем в этом вопросе, просто:
$ echo '1 2 3 4 5 6' | awk '{sub(/([^ ]+ +){3}/,"")}1' 4 5 6если вы хотите разместить ведущие пробелы и непустые пробелы, но снова с FS по умолчанию, то это:
$ echo ' 1 2 3 4 5 6' | awk '{sub(/[[:space:]]*([^[:space:]]+[[:space:]]+){3}/,"")}1' 4 5 6если у вас есть FS, который вы не можете отрицать в наборе символов, вы можете сначала преобразовать его в один символ (RS идеально подходит, если это один символ, так как RS не может появиться в поле, иначе рассмотрим SUBSEP), затем применить подстановку интервала RE, а затем преобразовать в OFS. например, если цепи "."с разделенными полями:
$ echo '1...2.3.4...5....6' | awk -F'[.]+' '{gsub(FS,RS);sub("([^"RS"]+["RS"]+){3}","");gsub(RS,OFS)}1' 4 5 6очевидно, что если OFS-это один символ, и он не может отображаться в полях ввода, вы можете уменьшить это к:
$ echo '1...2.3.4...5....6' | awk -F'[.]+' '{gsub(FS,OFS); sub("([^"OFS"]+["OFS"]+){3}","")}1' 4 5 6тогда у вас есть та же проблема, что и со всеми решениями на основе цикла, которые переназначают поля-FSs преобразуются в OFSs. Если это проблема, то вам нужно заглянуть в patsplit ГНУ соколы' (функция).
почти все ответы в настоящее время добавляют либо начальные пробелы, конечные пробелы или некоторые другие проблемы с разделителями. Чтобы выбрать из четвертого поля, где разделитель-пробел, а выходной разделитель-один пробел, используйте
awkбудет:awk '{for(i=4;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' fileчтобы параметризовать начальное поле, вы можете сделать:
awk '{for(i=n;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' n=4 fileа также поле окончания:
awk '{for(i=n;i<=m=(m>NF?NF:m);i++)printf "%s",$i (i==m?ORS:OFS)}' n=4 m=10 file
еще один способ избежать использования инструкции print:
$ awk '{===""}sub("^"FS"*","")' fileв awk, когда условие истинно печать является действием по умолчанию.
Я не могу поверить, что никто не предложил простую оболочку:
while read -r a b c d; do echo "$d"; done < file
варианты от 1 до 3 имеют проблемы с несколькими пробелами (но просты). Это является причиной для разработки вариантов 4 и 5, которые обрабатывают несколько пробелов без проблем. Конечно, если варианты 4 или 5 используются с
1n=0оба сохранят любые ведущие пробелы какn=0значит нет разделения.простое решение для вырезания (работает с одиночными разделителями):
2$ echo '1 2 3 4 5 6 7 8' | cut -d' ' -f4- 4 5 6 7 8форсирование awk re-calc иногда решите проблему (работает с некоторыми версиями awk) добавленных ведущих пространств:
3$ echo '1 2 3 4 5 6 7 8' | awk '{ ==="";=;} NF=NF' 4 5 6 7 8печать каждого поля, сформированного с помощью
printfдаст больше контроля:$ echo ' 1 2 3 4 5 6 7 8 ' | awk -v n=3 '{ for (i=n+1; i<=NF; i++){printf("%s%s",$i,i==NF?RS:OFS);} }' 4 5 6 7 8однако все предыдущие ответы меняют все FS между полями на OFS. Давайте построим несколько решений для этого.
4цикл с sub для удаления полей и разделителей является более портативным и не вызывает изменения FS на ОФС:
$ echo ' 1 2 3 4 5 6 7 8 ' | awk -v n=3 '{ for(i=1;i<=n;i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",);} } 1 ' 4 5 6 7 8Примечание: "^["FS"]* " должен принимать входные данные с ведущими пробелами.
5вполне возможно построить решение, которое не добавляет дополнительные начальные или конечные пробелы, а сохраняет существующие пробелы с помощью функции
gensubот GNU awk, как это:$ echo ' 1 2 3 4 5 6 7 8 ' | awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }' 4 5 6 7 8он также может быть использован для замены списка полей с учетом количества
n:$ echo ' 1 2 3 4 5 6 7 8 ' | awk -v n=3 '{ a=gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); b=gensub("^(.*)("a")","\1",1); print "|"a"|","!"b"!"; }' |4 5 6 7 8 | ! 1 2 3 !конечно, в таком случае OFS используется для разделения обеих частей строки, и конечное пустое пространство полей по-прежнему печатается.
Примечание 1:
["FS"]*используется для разрешения лидирующих пробелов во входной строке.
Cut имеет флаг --complement, который позволяет легко (и быстро) удалять столбцы. Полученный синтаксис аналогичен тому, что вы хотите сделать-сделать решение проще для чтения/понимания. Дополнение также работает для случая, когда вы хотите удалить несмежные столбцы.
$ foo='1 2 3 %s 5 6 7' $ echo "$foo" | cut --complement -d' ' -f1-3 %s 5 6 7 $
Perl решение, которое не добавляет ведущие или конечные пробелы:
perl -lane 'splice @F,0,3; print join " ",@F' fileperl
@Fautosplit массив начинается с индекса0в то время как awk поля начинаются с
Perl решение для данных, разделенных запятыми:
perl -F, -lane 'splice @F,0,3; print join ",",@F' file
Python решение:
python -c "import sys;[sys.stdout.write(' '.join(line.split()[3:]) + '\n') for line in sys.stdin]" < file
для меня самым компактным и совместимым решением на запрос
$ a='1 2\t \t3 4 5 6 7 \t 8\t '; $ echo -e "$a" | awk -v n=3 '{while (i<n) {i++; sub( FS"*", "")}; print }'и если у вас есть больше строк для обработки, как например file фу.txt, не забудьте сбросить i до 0:
$ awk -v n=3 '{i=0; while (i<n) {i++; sub( FS"*", "")}; print }' foo.txtблагодаря вашему форуму.
поскольку я был раздражен первым высоко оцененным, но неправильным ответом, я нашел достаточно, чтобы написать ответ там, и здесь неправильные ответы отмечены как таковые, вот мой бит. Мне не нравятся предлагаемые решения, поскольку я не вижу причин делать ответ таким сложным.
у меня есть журнал, где после $5 с IP-адресом может быть больше текста или нет текста. Мне нужно все, от IP-адреса до конца строки, если там будет что-нибудь после $5. В моем случае это фактически с программой awk, не проявляющаяся заинтересовала, так что программисты должны решить проблему. Когда я пытаюсь удалить первые 4 поля, используя старый красивый и самый популярный, но совершенно неправильный ответ:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three" | awk '{====""; printf "[%s]\n", }'он выплевывает неправильный и бесполезный ответ (я добавил [], чтобы продемонстрировать):
[ 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(,28)}'который производит желаемый результат:
[37.244.182.218 one two three]
это не очень далеко от некоторых из предыдущих ответов, но не решить пару вопросов:
cols.sh:#!/bin/bash awk -v s= '{for(i=s; i<=NF;i++) printf "%-5s", $i; print "" }'который теперь можно вызвать с аргументом, который будет стартовым столбцом:
$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 3 3 4 5 6 7 8 9 10 11 12 13 14или:
$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 7 8 9 10 11 12 13 14это 1-индексированный; если вы предпочитаете нулевой индексации, используйте .
более того, если вы хотите иметь аргументы для начального индекса и конечный индекс, изменить файл к:
#!/bin/bash awk -v s= -v e= '{for(i=s; i<=e;i++) printf "%-5s", $i; print "" }'например:
$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 9 7 8 9The
%-5sвыравнивает результат в виде столбцов шириной 5 символов; если этого недостаточно, увеличьте число или используйте%s(с пробелом), а если вы не заботитесь о выравнивании.
решение на основе AWK printf, которое позволяет избежать проблемы % и уникально тем, что оно ничего не возвращает (без возвращаемого символа), если для печати требуется менее 4 столбцов:
awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'тестирование:
$ x='1 2 3 %s 4 5 6' $ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }' %s 4 5 6 $ x='1 2 3' $ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }' $ x='1 2 3 ' $ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }' $
Comments