Ответ 1
Вы пробовали:
echo "12|23|11" | awk '{split($0,a,"|"); print a[3],a[2],a[1]}'
Как разбить строку, когда она содержит в ней символы канала |
.
Я хочу разбить их на массив.
Я пробовал
echo "12:23:11" | awk '{split($0,a,":"); print a[3] a[2] a[1]}'
Что отлично работает. Если моя строка похожа на "12|23|11"
, то как мне разбить их на массив?
Вы пробовали:
echo "12|23|11" | awk '{split($0,a,"|"); print a[3],a[2],a[1]}'
Чтобы разбить строку на массив в 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() (т.е. количество элементы в массиве).
Пожалуйста, будьте более конкретными! Что значит "это не работает"? Отправьте точный результат (или сообщение об ошибке), версию ОС и 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 полей.
echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
должен работать.
Мне не нравится решение 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 внутренняя переменная:
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
Шутка?:)
Как насчет 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
поэтому я думаю, что он работает в конце концов..