Как разбить строку с разделителями на массив в awk?

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

Я пробовал

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

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

Ответ 1

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

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

Ответ 2

Чтобы разбить строку на массив в 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
:::

Процитировать man-страницу:

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

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

Ответ 3

Пожалуйста, будьте более конкретными! Что значит "это не работает"? Отправьте точный результат (или сообщение об ошибке), версию ОС и 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 вам понадобится использовать POSIX awk (/usr/xpg4/bin/awk), чтобы правильно обработать 4000 полей.

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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

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]}'

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

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

Ответ 7

Шутка?:)

Как насчет 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

поэтому я думаю, что он работает в конце концов..