Использование awk для печати всех столбцов от n-го до последнего
эта строка работала, пока у меня не было пробелов во втором поле.
svn status | grep '!' | gawk '{print ;}' > removedProjs
есть ли способ заставить awk печатать все в $2 или больше? ($3, $4.. пока у нас больше нет колонок?)
полагаю, я должен добавить, что я делаю это в среде Windows с Cygwin.
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 }'
где-F "" определяет разделитель для использования awk. В моем случае это пробел, который также является разделителем по умолчанию для awk. Это означает, что-F" " можно игнорировать.
где NF определяет общее количество полей / столбцов. Поэтому цикл начнется от 4-го поля до последнего поля / столбца.
где $N возвращает значение N-го поля. Поэтому print $i будет печатать текущее поле / столбец на основе количества циклов.
большинство решений с awk оставляют пространство. Варианты здесь избегают этой проблемы.
1простое решение для вырезания (работает только с одиночными разделителями):
2command | cut -d' ' -f3-принудительное повторное вычисление awk иногда удаляет добавленное ведущее пространство (OFS), удаляя первые поля (работает с некоторыми версиями awk):
3command | awk '{ =="";=;} NF=NF'печать каждого поля в формате
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]*это принять вход с ведущими пробелами.5$ 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вполне возможно построить решение, которое не добавляет дополнительные (начальные или конечные) пробелы и сохраняет существующие пробелы с помощью функции
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 }'
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 '{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
этой
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