Как распечатать это с помощью AWK?

У меня есть файл, который выглядит так:

1 543423 34354 
2 5654656 3423 xyz_1378,xyz_1379
3 4645656 34234354 xyz_1384,xyz_1385
4 5654 78678 xyz_1390,xyz_1391,xyz_1392
5 54654 76867 xyz_1411,xyz_1412,xyz_1413
6 54654 8678 
7 56546 67867 xyz_1711
8 678 7867 
9 76867 7876 xyz_2940
10 6786 678678 xyz_3101,xyz_3102,xyz_3103,xyz_3104,xyz_3105,xyz_3106,xyz_3107
11 67867 78678 

Обратите внимание, что он содержит 4 поля, разделенных пробелом. последнее (четвертое) поле может быть пустым и содержать несколько значений, разделенных запятыми.

Я хотел бы напечатать все значения из последней строки, по одному в строке. как я могу это сделать (желательно с помощью awk)?

ОБНОВЛЕНИЕ: мне нужно сделать это в пакетном режиме для многих файлов (получает объединенный вывод всех файлов вместе).

Это работает:

for x in *; do awk '{print $4}' $x/filename | awk --field-separator="," '{if ($0 != "") {for (i=1; i<NF+1; i++) print $i}}'; done;

и возвращает что-то вроде

xyz_1378
xyz_1221
xyz_97
xyz_132523
xyz_242

Единственное, чего мне сейчас не хватает, так это того, что я хочу, чтобы каждая из приведенных выше строк начиналась с дополнительного поля — $x (тот, что из цикла for).

Я попытался изменить print $i на print $x,$i" butx`, похоже, он не распознается правильно в этой области. Любые идеи?

Спасибо!


awk
person David B    schedule 13.09.2010    source источник
comment
Когда вы говорите, что я хотел бы напечатать все значения из последней строки, по одному в строке. ты имеешь в виду последнюю колонку?   -  person Dennis Williamson    schedule 13.09.2010


Ответы (3)


Используйте параметр awk -v для передачи переменной в сценарий awk вместо того, чтобы полагаться на подстановку оболочки. Кроме того, вам нужен только один вызов awk

for dir in *; do 
    awk -v "dir=$dir" '
        NF==4 {
            n = split($4, a, ",")
            for (i=1; i<=n; i++) {print dir "\t" a[i]}
        }
    ' "$dir/filename"
done

или, если вы не против увидеть "dir/filename":

awk '
    NF==4 {
        n = split($4, a, ",")
        for (i=1; i<=n; i++) {print FILENAME "\t" a[i]}
    }
' */filename

Если у вас огромное количество каталогов, ваша оболочка может задохнуться при раскрытии «*/filename», поэтому используйте find и xargs:

find . -type f -name filename -print0 | xargs -0 awk '...'

(требуется GNU find/xargs для опций -print0/-0)

person glenn jackman    schedule 13.09.2010
comment
Небольшой комментарий: вместо for (i=1; i<=n; i++) можно использовать более простой for (i in a), если порядок не важен. - person TrueY; 22.04.2013

Вероятно, вы можете изменить один из операторов в вашей команде на

awk '{print FILENAME "," $4}' $x

а затем работать над выходом этого.

FILENAME — это внутренняя переменная awk для получения имени файла, который обрабатывается.

person Vijay    schedule 14.09.2010

Используйте NF>=4 в качестве условия, чтобы увидеть, есть ли что-нибудь в поле. Затем split($4,a,/,/) даст вам массив a со всеми значениями. Поместите это в большой массив результатов:

NF>=4 {
    n = split($4, a, /,/);
    for( i=1; i<=n; i++ ) {
        result[a[i]] = 0;
    }
}

и напечатайте его в конце:

END {
    for( val in result ) {
        print val;
    }
}

Если вы хотите, чтобы это отсортировано, отфильтруйте вывод, пропустив через sort(1)

person Aaron Digulla    schedule 13.09.2010
comment
Я пробовал тестировать, но это печатает от 1 до 7, каждое в строке. я где-то ошибся? - person Adriano Varoli Piazza; 13.09.2010
comment
-1: Кажется, это печатает последние цифры значений последней строки, которые по совпадению идут от 1 до 7. - person Adriano Varoli Piazza; 13.09.2010
comment
Извините, я забыл, что for(x in y) не работает с массивами. Исправлено. - person Aaron Digulla; 14.09.2010
comment
Также if($4) возвращает false, если $4 оценивается как числовой ноль. Мы не знаем фактических данных, поэтому, насколько нам известно, это возможно. if(length($4)) может быть более безопасной ставкой. - person ghoti; 02.11.2015
comment
@ghoti: теперь я использую NF>=4, как и другие ответы - person Aaron Digulla; 02.11.2015