Слишком громоздко:
awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things
Слишком громоздко:
awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things
Решение, которое не добавляет лишние начальные или конечные пробелы:
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-7
Sudo_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-7
EdMorton предоставляет решение, сохраняющее оригинальные пробелы между полями:
$ echo '1 2 3 4 5 6 7' |
awk '{ sub(/([^ ]+ +){3}/,"") }1' |
tr ' ' '-'
4---5----6-7
BinaryZebra также предлагает два великолепных решения:
(эти решения даже сохраняют конечные пробелы из исходной строки)
$ 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"]+","",$0);} } 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 $0}' | 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 $0}' n=4 | tr ' ' '-'
4-5-6-7
Все остальные ответы до сентября 2013 года хороши, но добавьте лишние пробелы:
Пример ответа с добавлением лишних пробелов:
$ echo '1 2 3 4 5 6 7' |
awk '{$1=$2=$3=""}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-------
awk '{for(i=1;i<4;i++) $i="";print}' file
использовать вырезать
$ cut -f4-13 file
или если вы настаиваете на awk, а $13 - последнее поле
$ awk '{$1=$2=$3="";print}' file
еще
$ awk '{for(i=4;i<=13;i++)printf "%s ",$i;printf "\n"}' file
Попробуйте следующее:
awk '{ $1=""; $2=""; $3=""; print $0 }'
Правильный способ сделать это - с интервалом 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, который RE не может отрицать в наборе символов, вы можете сначала преобразовать его в один char (RS идеален, если он один char, так как RS CAN NOT не отображается в пределах поле, в противном случае рассмотрите 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 является одиночным char И он не может появиться в полях ввода, вы можете уменьшить это:
$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,OFS); sub("([^"OFS"]+["OFS"]+){3}","")}1'
4 5 6
Тогда у вас есть та же проблема, что и для всех решений на основе петли, которые переназначают поля - FS преобразуются в OFS. Если это проблема, вам нужно заглянуть в функцию patsplit() GNU awks.
Практически все ответы в настоящее время добавляют либо ведущие пробелы, либо конечные пробелы, либо некоторые другие проблемы с разделителями. Чтобы выбрать из четвертого поля, где разделитель является пробелом, а разделитель вывода - одним пробелом, используя 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
awk '{$1=$2=$3="";$0=$0;$1=$1}1'
Ввод
1 2 3 4 5 6 7
Выход
4 5 6 7
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) print $i }'
Другой способ избежать использования оператора печати:
$ awk '{$1=$2=$3=""}sub("^"FS"*","")' file
В awk, когда условие истинно, это действие по умолчанию.
Не могу поверить, что никто не предлагал простой shell:
while read -r a b c d; do echo "$d"; done < file
Варианты с 1 по 3 имеют проблемы с несколькими пробелами (но просты).
Именно по этой причине разрабатываются варианты 4 и 5, которые без проблем обрабатывают множество белых пространств.
Конечно, если опции 4 или 5 используются с n=0
, оба сохраняют любые ведущие пробелы, поскольку n=0
означает отсутствие расщепления.
Простое решение (работает с одиночными разделителями):
$ echo '1 2 3 4 5 6 7 8' | cut -d' ' -f4-
4 5 6 7 8
Принудительное перевычисление awk иногда решает проблему (работает с некоторыми версиями awk) добавленных ведущих пробелов:
$ echo '1 2 3 4 5 6 7 8' | awk '{ $1=$2=$3="";$0=$0;} 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. Давайте построим пару решений.
Цикл с sub для удаления полей и разделителей более переносим и не вызывает изменения FS в OFS:
$ echo ' 1 2 3 4 5 6 7 8 ' |
awk -v n=3 '{ for(i=1;i<=n;i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 '
4 5 6 7 8
ПРИМЕЧАНИЕ: "^ [" FS "] *" - принять ввод с ведущими пробелами.
Вполне возможно создать решение, которое не добавит лишних пробелов в начале или конце, и сохранить существующие пробелы, используя функцию 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
Он также может использоваться для замены списка полей с учетом count 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"]*
используется, чтобы позволить ведущие пробелы в строке ввода.
Решение Perl, которое не добавляет прокрутки в начало или конец:
perl -lane 'splice @F,0,3; print join " ",@F' file
Массив autosplit perl @F
начинается с индекса 0
, тогда как awk-поля начинаются с $1
Решение 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
Cut имеет флаг -complement, который упрощает (и быстро) удаление столбцов. Полученный синтаксис аналогичен тому, что вы хотите сделать, что упрощает чтение и понимание. Приложение также работает для случая, когда вы хотите удалить несмежные столбцы.
$ foo='1 2 3 %s 5 6 7'
$ echo "$foo" | cut --complement -d' ' -f1-3
%s 5 6 7
$
Для меня наиболее компактным и совместимым решением для запроса является
$ a='1 2\t \t3 4 5 6 7 \t 8\t ';
$ echo -e "$a" | awk -v n=3 '{while (i<n) {i++; sub($1 FS"*", "")}; print $0}'
И если у вас больше строк для обработки, например, для файла foo.txt, не забудьте reset я до 0:
$ awk -v n=3 '{i=0; while (i<n) {i++; sub($1 FS"*", "")}; print $0}' foo.txt
Спасибо вашему форуму.
Поскольку я был раздражен первым высоко голосованным, но неправильным ответом, я нашел достаточно, чтобы написать ответ там, и здесь неправильные ответы отмечены как таковые, вот мой кусочек. Мне не нравятся предлагаемые решения, так как я не вижу причин, чтобы сделать ответ таким сложным.
У меня есть журнал, где после 5 долларов с IP-адресом может быть больше текста или нет текста. Мне нужно все, от IP-адреса до конца строки, если что-то будет после 5 долларов. В моем случае это на самом деле в программе awk, а не в awk oneliner, поэтому 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)}'
который производит желаемый результат:
[37.244.182.218 one two three]
Я нашел эту другую возможность, может быть, это может быть полезно также...
awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file
Примечание: 1. Для табличных данных и от столбца $ 1 до $ 14
Используйте вырезать:
cut -d <The character between characters> -f <number of first column>,<number of last column> <file name>
Например: если у вас есть file1
содержащий: car.is.nice.equal.bmw
Выполнить: cut -d. -f1,3 file1
cut -d. -f1,3 file1
напечатает car.is.nice
Это не очень далеко от некоторых предыдущих ответов, но решает пару проблем:
cols.sh
:
#!/bin/bash
awk -v s=$1 '{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-индекс; если вы предпочитаете нулевое индексирование, вместо этого используйте i=s + 1
.
Кроме того, если вы хотите иметь аргументы для начального индекса и конечного индекса, измените файл на:
#!/bin/bash
awk -v s=$1 -v e=$2 '{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 9
%-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) }'
$