Использование awk для печати всех столбцов от n-го до последнего
эта строка работала, пока у меня не было пробелов во втором поле.
svn status | grep '!' | gawk '{print ;}' > removedProjs
есть ли способ заставить awk печатать все в $2 или больше? ($3, $4.. пока у нас не закончатся колонки?)
полагаю, я должен добавить, что я делаю это в среде Windows с Cygwin.
24 ответов
напечатает все, кроме самого первого столбца:
awk '{=""; print }' somefile
напечатает все, кроме двух первых столбцов:
awk '{==""; print }' somefile
есть дубликат вопроса с проще ответить использование cut:
svn status | grep '\!' | cut -d\ -f2-
-d
задает разделитель (пробел), -f
задает список столбцов (все начиная со 2-ой)
вы можете использовать for-loop для циклической печати полей $2 через $NF (встроенная переменная, представляющая количество полей в строке).
изменить: Поскольку "печать" добавляет новую строку, вы захотите буферизировать результаты:
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простое решение для вырезания (работает только с одиночными разделителями):
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:
Примечание: на ^[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
он также может использоваться для замены группы полей с учетом count 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 Стек Обмен) - добавить псевдоним ~/.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 mode-разделить входные линии в массив @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
to 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
способ объявления локальных переменных.
я хочу расширить предлагаемые ответы на ситуацию, когда поля разделены, возможно,несколько пробельных символов - причина, по которой OP не использует cut
Я полагаю.
я знаю, что ОП спрашивает о awk
, а sed
подход будет работать здесь (пример с печатными столбцами от 5-го до последнего):
-
чистый подход sed
sed -r 's/^\s*(\S+\s+){4}//' somefile
объяснение:
- это стандартный способ выполнения подстановки
-
^\s*
соответствует любому последовательному пробелу в начале строки -
\S+\s+
означает столбец данных (символы без пробелов, за которыми следуют символы пробелов) -
(){4}
означает, что рисунок повторяется 4 раза.
-
sed и cut
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
- это n- й столбец отсчет от 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
решение от Крис Koknat это действительно только первые 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 |
из-за неправильного наиболее голосовали anwser с 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]