Распечатать все, кроме первых трех столбцов - PullRequest
109 голосов
/ 13 апреля 2010

Слишком громоздко:

awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things

Ответы [ 19 ]

75 голосов
/ 23 августа 2011
awk '{for(i=1;i<4;i++) $i="";print}' file
69 голосов
/ 13 апреля 2010

использовать вырезать

$ 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
48 голосов
/ 16 сентября 2013

Решение, которое не добавляет дополнительные начальные или конечные символы пробел :

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 года хороши, но добавьте лишние пробелы:

38 голосов
/ 13 апреля 2010

Попробуйте это:

awk '{ $1=""; $2=""; $3=""; print $0 }'
24 голосов
/ 16 сентября 2013

Правильный способ сделать это с интервалом 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, которую нельзя отрицать в наборе символов, вы можете сначала преобразовать ее в один символ (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

Тогда возникает та же проблема, что и со всеми решениями на основе петель, которые переназначают поля - FS преобразуются в OFS. Если это проблема, вам нужно обратиться к функции patsplit () GNU awks.

10 голосов
/ 16 сентября 2013

Почти все ответы в настоящее время добавляют либо начальные пробелы, конечные пробелы, либо некоторые другие разделители. Чтобы выбрать из четвертого поля, где разделитель - это пробел, а выходной разделитель - один пробел, используйте 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
6 голосов
/ 26 декабря 2014
awk '{$1=$2=$3="";$0=$0;$1=$1}1'

Input

1 2 3 4 5 6 7

Выход

4 5 6 7
4 голосов
/ 13 апреля 2010
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) print $i }'
3 голосов
/ 24 сентября 2015

Опции с 1 по 3 имеют проблемы с несколькими пробелами (но они просты). Это причина для разработки вариантов 4 и 5, которые обрабатывают несколько пробелов без проблем. Конечно, если опции 4 или 5 используются с n=0, оба сохранят все начальные пробелы, так как n=0 означает отсутствие разделения.

Вариант 1

Простое решение среза (работает с одиночными разделителями):

$ echo '1 2 3 4 5 6 7 8' | cut -d' ' -f4-
4 5 6 7 8

Вариант 2

Принудительный пересчет awk иногда решает проблему (работает с некоторыми версиями awk) добавленных начальных пробелов:

$ echo '1 2 3 4 5 6 7 8' | awk '{ $1=$2=$3="";$0=$0;} NF=NF'
4 5 6 7 8

Вариант 3

Печать каждого поля, отформатированного с помощью 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

Цикл с подпрограммой для удаления полей и разделителей является более переносимым и не вызывает смену 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 "] *" должен принимать ввод с начальными пробелами.

Вариант 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"]* используется для разрешения пробелов в строке ввода.

3 голосов
/ 22 июня 2014

Не могу поверить, что никто не предложил простую оболочку:

while read -r a b c d; do echo "$d"; done < file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...