Использование awk для печати всех столбцов от n-го до последнего - PullRequest
270 голосов
/ 03 июня 2010

Эта строка работала, пока во втором поле не было пробелов.

svn status | grep '\!' | gawk '{print $2;}' > removedProjs

есть ли способ заставить awk распечатать все за 2 доллара или больше? (3 доллара, 4 доллара ... пока у нас больше не будет столбцов?)

Полагаю, мне следует добавить, что я делаю это в среде Windows с Cygwin.

Ответы [ 24 ]

426 голосов
/ 03 июня 2010

напечатает все, кроме самого первого столбца:

awk '{$1=""; print $0}' somefile

напечатает все, кроме двух первых столбцов:

awk '{$1=$2=""; print $0}' somefile
90 голосов
/ 25 января 2012

Есть дублирующий вопрос с более простым ответом с использованием сокращения:

 svn status |  grep '\!' | cut -d\  -f2-

-d указывает разделитель (пробел) , -f указывает список столбцов (все начинаются со 2-го)

77 голосов
/ 03 июня 2010

Вы можете использовать цикл for для циклического прохождения полей печати от $ 2 до $ NF (встроенная переменная, которая представляет количество полей в строке).

Edit: Так как «print» добавляет новую строку, вам нужно буферизовать результаты:

awk '{out=""; for(i=2;i<=NF;i++){out=out" "$i}; print out}'

В качестве альтернативы используйте printf:

awk '{for(i=2;i<=NF;i++){printf "%s ", $i}; printf "\n"}'
23 голосов
/ 14 апреля 2011
awk '{out=$2; for(i=3;i<=NF;i++){out=out" "$i}; print out}'

Мой ответ основан на ответа VeeArr , но я заметил, что он начался с пробела, прежде чем он напечатал второй столбец (и остальные). Поскольку у меня есть только 1 очко репутации, я не могу это комментировать, поэтому здесь это выглядит как новый ответ:

начните с "out" в качестве второго столбца, а затем добавьте все остальные столбцы (если они существуют). Это хорошо, пока есть второй столбец.

12 голосов
/ 12 июня 2013

Я лично попробовал все ответы, упомянутые выше, но большинство из них были немного сложными или просто не правы. Самый простой способ сделать это с моей точки зрения:

awk -F" " '{ for (i=4; i<=NF; i++) print $i }'
  1. Где -F "" определяет разделитель для использования в awk. В моем случае это пробел, который также является разделителем по умолчанию для awk. Это означает, что -F "" можно игнорировать.

  2. Где NF определяет общее количество полей / столбцов. Поэтому цикл начнется с 4-го поля до последнего поля / столбца.

  3. Где $ N возвращает значение N-го поля. Поэтому print $ i будет печатать текущее поле / столбец на основе количества циклов.

12 голосов
/ 25 сентября 2015

Большинство решений с awk оставляют пробел. Опции здесь позволяют избежать этой проблемы.

Вариант 1

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

command | cut -d' ' -f3-

Вариант 2

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

command | awk '{ $1=$2="";$0=$0;} NF=NF'

Вариант 3

Печать каждого поля, отформатированного с помощью printf, даст больше контроля:

$ in='    1    2  3     4   5   6 7     8  '
$ echo "$in"|awk -v n=2 '{ for(i=n+1;i<=NF;i++) printf("%s%s",$i,i==NF?RS:OFS);}'
3 4 5 6 7 8

Однако все предыдущие ответы меняют все повторяющиеся FS между полями на OFS. Давайте создадим пару вариантов, которые этого не делают.

Вариант 4 (рекомендуется)

Цикл с подпрограммой для удаления полей и разделителей спереди.
И используя значение FS вместо пробела (который можно изменить).
Является более переносимым и не вызывает смену FS на OFS: ПРИМЕЧАНИЕ: ^[FS]* должен принимать ввод с начальными пробелами.

$ in='    1    2  3     4   5   6 7     8  '
$ echo "$in" | awk '{ n=2; a="^["FS"]*[^"FS"]+["FS"]+";
  for(i=1;i<=n;i++) sub( a , "" , $0 ) } 1 '
3     4   5   6 7     8

Вариант 5

Вполне возможно построить решение, которое не добавляет лишние (начальные или конечные) пробелы и сохраняет существующие пробелы (я), используя функцию gensub из GNU awk, как это:

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=2 'BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; }
          { print(gensub(a""b""c,"",1)); }'
3     4   5   6 7     8 

Он также может использоваться для замены группы полей по количеству n:

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=2 'BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; }
          {
            d=gensub(a""b""c,"",1);
            e=gensub("^(.*)"d,"\\1",1,$0);
            print("|"d"|","!"e"!");
          }'
|3     4   5   6 7     8  | !    1    2  !

Конечно, в таком случае OFS используется для разделения обеих частей строки, а конечный пробел в полях все еще печатается.

ПРИМЕЧАНИЕ: [FS]* используется для разрешения пробелов в строке ввода.

6 голосов
/ 27 ноября 2013

Это меня очень раздражало, я сел и написал cut -подобный синтаксический анализатор спецификации поля, протестированный с GNU Awk 3.1.7.

Сначала создайте новый скрипт библиотеки Awk с именем pfcut, например,

sudo nano /usr/share/awk/pfcut

Затем вставьте скрипт ниже и сохраните. После этого вот как выглядит использование:

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-4"); }'
t1 t2 t3 t4

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("2-"); }'
t2 t3 t4 t5 t6 t7

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7

Чтобы не вводить все это, я думаю, что лучшее, что можно сделать (см. Иначе Автоматически загружать пользовательскую функцию при запуске с помощью awk? - Unix & Linux Stack Exchange ) - добавить псевдоним к ~/.bashrc ; например с:

$ echo "alias awk-pfcut='awk -f pfcut --source'" >> ~/.bashrc
$ source ~/.bashrc     # refresh bash aliases

... тогда вы можете просто позвонить:

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk-pfcut '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7

Вот источник сценария pfcut:

# pfcut - print fields like cut
#
# sdaau, GNU GPL
# Nov, 2013

function spfcut(formatstring)
{
  # parse format string
  numsplitscomma = split(formatstring, fsa, ",");
  numspecparts = 0;
  split("", parts); # clear/initialize array (for e.g. `tail` piping into `awk`)
  for(i=1;i<=numsplitscomma;i++) {
    commapart=fsa[i];
    numsplitsminus = split(fsa[i], cpa, "-");
    # assume here a range is always just two parts: "a-b"
    # also assume user has already sorted the ranges
    #print numsplitsminus, cpa[1], cpa[2]; # debug
    if(numsplitsminus==2) {
     if ((cpa[1]) == "") cpa[1] = 1;
     if ((cpa[2]) == "") cpa[2] = NF;
     for(j=cpa[1];j<=cpa[2];j++) {
       parts[numspecparts++] = j;
     }
    } else parts[numspecparts++] = commapart;
  }
  n=asort(parts); outs="";
  for(i=1;i<=n;i++) {
    outs = outs sprintf("%s%s", $parts[i], (i==n)?"":OFS); 
    #print(i, parts[i]); # debug
  }
  return outs;
}

function pfcut(formatstring) {
  print spfcut(formatstring);
}
5 голосов
/ 03 июня 2010

Будет ли это работать?

awk '{print substr($0,length($1)+1);}' < file

Впрочем, впереди остаются пробелы.

5 голосов
/ 11 ноября 2012

Распечатка столбцов, начиная с # 2 (вывод не будет заканчиваться пробелом в начале):

ls -l | awk '{sub(/[^ ]+ /, ""); print $0}'
4 голосов
/ 06 июля 2012
echo "1 2 3 4 5 6" | awk '{ $NF = ""; print $0}'

этот использует awk для печати всех, кроме последнего поля

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...