Использование awk для печати всех столбцов от n-го до последнего



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



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


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



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

910   24  

24 ответов:

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

awk '{=""; print }' somefile

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

awk '{==""; print }' somefile

есть дубликат вопроса с более простой ответ через шлиц:

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

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

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

изменить: Поскольку "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"}'
awk '{out=; for(i=3;i<=NF;i++){out=out" "$i}; print out}'

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

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

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

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

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

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

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

1

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

command | cut -d' ' -f3-
2

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

command | awk '{ =="";=;} 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 (рекомендуется)

цикл с sub для удаления полей и разделителей спереди.
И используя значение FS вместо пространства (которое может быть изменено).
Является более портативным и не вызывает изменения FS на OFS: Примечание: The ^[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 , "" ,  ) } 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,);
            print("|"d"|","!"e"!");
          }'
|3     4   5   6 7     8  | !    1    2  !

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

Примечание:[FS]* используется для разрешения лидирующих пробелов во входной строке.

это так меня раздражало, что я сел и написал 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);
}

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

ls -l | awk '{sub(/[^ ]+ /, ""); print }'

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

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

Он оставляет пробелы перед.

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

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

это то, что я предпочел из всех рекомендаций:

печать с 6-го по последней колонке.

ls -lthr | awk '{out=; for(i=7;i<=NF;i++){out=out" "$i}; print out}'

или

ls -lthr | awk '{ORS=" "; for(i=6;i<=NF;i++) print $i;print "\n"}'
awk '{ for(i=3; i<=NF; ++i) printf $i""FS; print "" }'

lauhub предложил это правильное, простое и быстрое решение здесь

Если вам нужны конкретные столбцы, напечатанные с произвольной чертой:

awk '{print  "  " }'

col#3 col#4

awk '{print  "anything" }'

col#3anythingcol#4

Так что если у вас есть пробелы в столбце будет две колонки, но вы можете соединить его с любым разделителем или без него.

на Perl решение:

perl -lane 'splice @F,0,1; print join " ",@F' file

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

  • -n цикл вокруг каждой строки входного файла, не печатайте автоматически каждую строку

  • -l удаляет новые строки перед обработкой, а затем добавляет их обратно

  • -a режим autosplit-разделить входные строки в массив @F. По умолчанию разбиение на пробел

  • -e выполнить код perl

splice @F,0,1 чисто удаляет столбец 0 из массива @F

join " ",@F соединяет элементы массива @F, используя пробел между каждым элементом


Python решение:

python -c "import sys;[sys.stdout.write(' '.join(line.split()[1:]) + '\n') for line in sys.stdin]" < file

Это будет работать, если вы используете Bash, и вы можете использовать столько "x", сколько элементов вы хотите отбросить, и он игнорирует несколько пробелов, если они не экранированы.

while read x b; do echo "$b"; done < filename

если вы не хотите переформатировать часть строки, которую вы не отрубаете, лучшее решение, которое я могу придумать, написано в моем ответе:

как напечатать все столбцы после определенного числа с помощью awk?

он рубит то, что находится перед заданным номером поля N, и печатает всю остальную часть строки, включая номер поля N и сохраняя исходный интервал (он не переформатируется). Это не имеет значения, если строка поля также появляется где-то еще в очереди.

определения функции:

fromField () { 
awk -v m="\x01" -v N="" '{$N=m$N; print substr(,index(,m)+1)}'
}

и использовать его так:

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost 

выход поддерживает все, включая конечные пробелы

в вашем конкретном случае:

svn status | grep '\!' | fromField 2 > removedProjs

если ваш файл / поток не содержит символов новой строки в середине строк (вы можете использовать другой разделитель записей), вы можете использовать:

awk -v m="\x0a" -v N="3" '{$N=m$N ;print substr(, index(,m)+1)}'

первый случай будет неудачным только в файлах / потоках, которые содержат редкий шестнадцатеричный символ номер 1

Perl:

@m=`ls -ltr dir | grep ^d | awk '{print $6,$7,$8,$9}'`;
foreach $i (@m)
{
        print "$i\n";

}

этой awk функция возвращает подстроку , что включает в себя поля из begin до end:

function fields(begin, end,    b, e, p, i) {
    b = 0; e = 0; p = 0;
    for (i = 1; i <= NF; ++i) {
        if (begin == i) { b = p; }
        p += length($i);
        e = p;
        if (end == i) { break; }
        p += length(FS);
    }
    return substr(, b + 1, e - b);
}

чтобы получить все, начиная с поля 3:

tail = fields(3);

чтобы получить раздел это охватывает поля от 3 до 5:

middle = fields(3, 5);

b, e, p, i бред в списке параметров функции-это просто awk способ объявления локальных переменных.

я хочу расширить предлагаемые ответы на ситуацию, когда поля разделены возможно несколько пробельных символов - причина, по которой ОП не использует cut Я полагаю.

я знаю, что ОП спрашивает о awk, а sed подход будет работать здесь (пример с печатными столбцами от 5-го до последнего):

  • чистый подход sed

    sed -r 's/^\s*(\S+\s+){4}//' somefile
    

    объяснение:

    • это стандартный способ выполнения подстановки
    • ^\s* соответствует любому последовательному пробелу в начале строки
    • \S+\s+ означает столбец данных (символы без пробелов, за которыми следуют символы пробелов)
    • (){4} означает, что рисунок повторяется 4 раза.
  • sed и вырезать

    sed -r 's/^\s+//; s/\s+/\t/g' somefile | cut -f5-
    

    просто заменив последовательные пробелы на одну вкладку;

  • tr и отрезать: tr также может быть использован для сжать подряд символы .

    tr -s [:blank:] <somefile | cut -d' ' -f5-
    

примеры Awk здесь выглядят сложными, вот простой синтаксис оболочки Bash:

command | while read -a cols; do echo ${cols[@]:1}; done

здесь 1 - это nth столбец считая от 0.


пример

учитывая это содержимое файла (in.txt):

c1
c1 c2
c1 c2 c3
c1 c2 c3 c4
c1 c2 c3 c4 c5

вот вывод:

$ while read -a cols; do echo ${cols[@]:1}; done < in.txt 

c2
c2 c3
c2 c3 c4
c2 c3 c4 c5

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

echo -e "a  b  c  d\te\t\tf g" | \
  perl -ne 'my @f = split /\s+/, $_, 3; printf "first: %s second: %s rest: %s", @f;'

преимущество по сравнению с perl решение от Крис Кокнат это действительно только первые n элементов отделяются от входной строки; остальная часть строки не разделяется вообще и поэтому остается полностью нетронутым. Мой пример демонстрирует это с помощью сочетания пробелов и вкладок.

чтобы изменить количество столбцов, которые должны быть извлечены, замените 3 в Примере с n+1.

ls -la | awk '{o=" "; for (i=5; i<=NF; i++) o=o" "$i; print o }'

С ответ не плохо, но естественный разнос ушел.
Пожалуйста, сравните его с этим:

ls -la | cut -d\  -f4-

тогда вы увидите разницу.

даже ls -la | awk '{==""; print}' который основан на ответ проголосовали лучше до сих пор не сохранить форматирование.

таким образом, я бы использовал следующее, И это также позволяет явные выборочные столбцы в начале:

ls -la | cut -d\  -f1,4-

обратите внимание, что каждое пространство количество столбцов тоже, поэтому, например, в приведенном ниже, столбцы 1 и 3 пусты, 2-это информация, а 4-это:

$ echo " INFO  2014-10-11 10:16:19  main " | cut -d\  -f1,3

$ echo " INFO  2014-10-11 10:16:19  main " | cut -d\  -f2,4
INFO 2014-10-11
$

Если вы хотите отформатировать текст, соедините свои команды с echo и используйте $0 для печати последнего поля.

пример:

for i in {8..11}; do
   s1="$i"
   s2="str$i"
   s3="str with spaces $i"
   echo -n "$s1 $s2" | awk '{printf "|%3d|%6s",,}'
   echo -en "$s3" | awk '{printf "|%-19s|\n", }'
done

принты:

|  8|  str8|str with spaces 8  |
|  9|  str9|str with spaces 9  |
| 10| str10|str with spaces 10 |
| 11| str11|str with spaces 11 |

из-за неверной наиболее upvoted ответ с 340 голосами, я только что потерял 5 минут своей жизни! Кто-нибудь пробовал этот ответ, прежде чем поднимать это? Очевидно, нет. Совершенно бесполезный.

у меня есть журнал, где после $5 с IP-адресом может быть больше текста или нет текста. Мне нужно все, от IP-адреса до конца строки, если там будет что-нибудь после $5. В моем случае это фактически программа awk, а не awk oneliner, поэтому awk должен решить проблему. Когда я пытаюсь удалите первые 4 поля, используя самый популярный, но совершенно неправильный ответ:

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218" | awk '{====""; printf "[%s]\n", }'

он выдает неправильный и бесполезный ответ (я добавил [..] чтобы продемонстрировать):

[    37.244.182.218 one two three]

есть даже некоторые sugestions, чтобы объединить substr с этим неправильным ответом. Как будто это осложнение-улучшение.

вместо этого, если столбцы фиксированной ширины до точки разреза и awk не требуется, правильный ответ:

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218" | awk '{printf "[%s]\n", substr(,28)}'

который производит желаемое вывод:

[37.244.182.218 one two three]

Comments

    Ничего не найдено.