Пользовательские разделители полей в awk с регулярным выражением: проблема с начальными пробелами и запятыми - PullRequest
1 голос
/ 09 марта 2020

Я искал решение для stackoverflow, нашел несколько связанных ответов, но не смог найти четкого решения своих сомнений. Я надеюсь, что я не задаю повторяющийся вопрос.

Давайте рассмотрим файл

cat > file << EOF
1 2  3 4, 5,, 6, 7
EOF

Я хочу использовать в качестве разделителя произвольное количество запятых и пробелов. С помощью awk, установив разделитель полей с помощью F "[,] *", я получаю желаемый результат, а именно:

awk -F"[ ,]+" '{print $1}' file --> 1
awk -F"[ ,]+" '{print $2}' file --> 2
awk -F"[ ,]+" '{print $3}' file --> 3
awk -F"[ ,]+" '{print $4}' file --> 4
awk -F"[ ,]+" '{print $5}' file --> 5
awk -F"[ ,]+" '{print $6}' file --> 6
awk -F"[ ,]+" '{print $7}' file --> 7

Однако, если у меня есть начальные пробелы, у меня проблема. Например:

с одним начальным пробелом

cat > file << EOF
 1 2  3 4, 5,, 6, 7
EOF

Я получаю

awk -F"[ ,]+" '{print $1}' file -->   
awk -F"[ ,]+" '{print $2}' file --> 1
awk -F"[ ,]+" '{print $3}' file --> 2
...

с двумя одинаковыми начальными пробелами

cat > file << EOF
  1 2  3 4, 5,, 6, 7
EOF
awk -F"[ ,]+" '{print $1}' file -->  
awk -F"[ ,]+" '{print $2}' file -->  1
awk -F"[ ,]+" '{print $3}' file -->  2
...

и так далее.

Однако проблема не только в пробелах. Например, с

cat > file << EOF
1,2,3,
EOF

у меня есть

awk -F"," '{print $1}' file -->   1
awk -F"," '{print $2}' file -->   2
awk -F"," '{print $3}' file -->   3
awk -F"," '{print $4}' file -->  

, что я и ожидаю, но с

cat > file << EOF
,1,2,3
EOF

я получаю

awk -F"," '{print $1}' file -->   
awk -F"," '{print $2}' file -->   1
awk -F"," '{print $3}' file -->   2
awk -F"," '{print $4}' file -->   3

и я не понимаю почему.

Кажется, что awk обрабатывает ведущие разделители по-другому. Возможно, я неправильно понял синтаксис регулярных выражений. Действительно, я не понимаю, почему установка -F "" ведущих пробелов обрабатывается надлежащим образом, тогда как установка -F "[] *" У меня та же проблема.

В заключение, это мои вопросы : почему я получаю эти результаты для начальных пробелов или начальных запятых и каков правильный синтаксис, чтобы рассматривать в качестве разделителей полей любое количество запятых и пробелов, независимо от того, являются ли они ведущими или нет.

1 Ответ

1 голос
/ 09 марта 2020

Да, есть некоторая несогласованность, я думаю, для удобства.

Разделитель по умолчанию игнорирует начальные / конечные пробелы

$ echo " 1 2 " | awk '{for(i=1;i<=NF;i++) print i"--> "$i}'
1--> 1
2--> 2

установка FS для пробелов ведет себя одинаково

$ echo " 1 2 " | awk -F' ' '{for(i=1;i<=NF;i++) print i"--> "$i}'
1--> 1
2--> 2

однако набор символов установлен.

$ echo " 1 2 " | awk -F'[ ]' '{for(i=1;i<=NF;i++) print i"--> "$i}'
1-->
2--> 1
3--> 2
4-->

, поскольку имеется 3 разделителя (поэтому предполагается наличие четырех полей). С разделителем запятых вы не получите поведение по умолчанию, а только последнюю версию.

Если вы хотите имитировать c поведение по умолчанию для запятой и пробела, вам нужно написать свою собственную обработку, что-то вроде этого

$ echo "   ,1 2," | 
  awk -F'[ ,]+' 'NF{if($1=="") {for(i=2;i<=NF;i++) $(i-1)=$i; NF--} 
                    if($NF=="") NF--} 
                   {for(i=1;i<=NF;i++) print i"--> "$i}'

1--> 1
2--> 2

Объяснение: если первое поле пустое, сдвинуть все поля на одну влево, уменьшить количество полей на единицу; аналогично, если последнее поле пусто, просто уменьшите количество полей. Последний оператор предназначен для печати полей по одному на строке по номеру позиции поля.

Обновление для обработки пустых строк добавьте защитную строку NF перед попыткой исправить поля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...