Как разбить строку с разделителями в массив в awk? - PullRequest
126 голосов
/ 04 ноября 2011

Как разбить строку, если она содержит символы трубы |. Я хочу разделить их, чтобы они были в массиве.

Я пытался

echo "12:23:11" | awk '{split($0,a,":"); print a[3] a[2] a[1]}'

Который работает нормально. Если моя строка похожа на "12|23|11", то как мне разбить их на массив?

Ответы [ 8 ]

206 голосов
/ 04 ноября 2011

Вы пробовали:

echo "12|23|11" | awk '{split($0,a,"|"); print a[3],a[2],a[1]}'
86 голосов
/ 25 марта 2016

Чтобы разбить строку на массив в awk, мы используем функцию split():

 awk '{split($0, a, ":")}'
 #           ^^  ^  ^^^
 #            |  |   |
 #       string  |   delimiter
 #               |
 #               array to store the pieces

Если разделитель не указан, используется FS, по умолчанию используется пробел:

$ awk '{split($0, a); print a[2]}' <<< "a:b c:d e"
c:d

Мы можем дать разделитель, например ::

$ awk '{split($0, a, ":"); print a[2]}' <<< "a:b c:d e"
b c

Что эквивалентно настройке через FS:

$ awk -F: '{split($0, a); print a[1]}' <<< "a:b c:d e"
b c

В gawk вы также можете указать разделитель в виде регулярного выражения:

$ awk '{split($0, a, ":*"); print a[2]}' <<< "a:::b c::d e" #note multiple :
b c

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

$ awk '{split($0, a, ":*", sep); print a[2]; print sep[1]}' <<< "a:::b c::d e"
b c
:::

Давайте процитируем справочную страницу GNU awk :

split (строка, массив [, fieldsep [, seps]])

Разделите строку на части, разделенные fieldsep и сохраните части в массив и разделительные строки в массиве seps . Первый кусок хранится в array[1], второй кусок в array[2] и так далее. Строковое значение третьего аргумента, fieldsep , является регулярным выражением, описывающим, где разделить string (почти как FS может быть регулярным выражением, описывающим, где разделить входные записи ). Если fieldsep опущен, используется значение FS . split() возвращает количество созданных элементов. seps - расширение gawk, с seps[i] - строка-разделитель между array[i] и array[i+1]. Если fieldsep представляет собой один пробел, то любой начальный пробел переходит в seps[0], а любой конечный пробел - в seps[n], где n - это возвращаемое значение split() (т.е. , количество элементов в массиве).

15 голосов
/ 04 ноября 2011

Пожалуйста, будьте более конкретны!Что вы подразумеваете под "это не работает"?Отправьте точный вывод (или сообщение об ошибке), вашу ОС и версию awk:

% awk -F\| '{
  for (i = 0; ++i <= NF;)
    print i, $i
  }' <<<'12|23|11'
1 12
2 23
3 11

Или, используя split:

% awk '{
  n = split($0, t, "|")
  for (i = 0; ++i <= n;)
    print i, t[i]
  }' <<<'12|23|11'
1 12
2 23
3 11

Редактировать: на Solaris youВам нужно будет использовать POSIX awk ( / usr / xpg4 / bin / awk ) для правильной обработки 4000 полей.

3 голосов
/ 22 октября 2018

На самом деле awk имеет функцию под названием «Переменная разделителя входных полей» ссылка . Вот как это использовать. Это не совсем массив, но он использует внутренние переменные $. Разбить простую строку проще.

echo "12|23|11" | awk 'BEGIN {FS="|";} { print $1, $2, $3 }'
3 голосов
/ 04 ноября 2011
echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
2 голосов
/ 10 февраля 2016

Мне не нравится решение echo "..." | awk ..., так как оно вызывает ненужные системные вызовы fork и exec.

Я предпочитаю решение Димитра с небольшим поворотом

awk -F\| '{print $3 $2 $1}' <<<'12|23|11'

Или немного более короткая версия:

awk -F\| '$0=$3 $2 $1' <<<'12|23|11'

В этом случае выходная запись соединяется, что является истинным условием, поэтому она печатается.

В этом конкретном случае перенаправление stdin можетизбавьтесь от установки внутренней переменной :

awk -v T='12|23|11' 'BEGIN{split(T,a,"|");print a[3] a[2] a[1]}'

Я использовал довольно давно, но в это можно сделатьвнутренними манипуляциями со строками.В первом случае исходная строка разделяется внутренним терминатором.Во втором случае предполагается, что строка всегда содержит пары цифр, разделенные одним символьным разделителем.

T='12|23|11';echo -n ${T##*|};T=${T%|*};echo ${T#*|}${T%|*}
T='12|23|11';echo ${T:6}${T:3:2}${T:0:2}

Результат во всех случаях равен

112312
2 голосов
/ 04 ноября 2011
echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'

должно работать.

1 голос
/ 04 ноября 2011

Шутка? :)

Как насчет echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'

Это мой вывод:

p2> echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
112312

так что, думаю, все-таки работает

...