2015-05-15 2 views
1

У меня есть этот файл:Разделение csv с awk: как считать возврат?

field1|field2|field3|f41;f42|f5 
field1|field2|field3|f41|f5| 
field1|field2|field3|f41;f42;f43|f5 

Я хочу, чтобы разобрать его и получить:

field1|field2|field3|f41|f5 
field1|field2|field3|f42|f5 
... 

Короче сделать subparsing по semicolumn в поле 4. Мой AWK сценария является следующее:

awk < myfile.txt -F\| '{ 
n=split($4,a,";"); 
print $1 
for(i=0; ++i <= n;) 
print $1"|"$2"|"$3"|"a[i]"|"$5"|"; 
}' 

он работает, в любом случае для линий, не заканчивающихся на «|» Я получаю первый символ следующей линии, исчезающей! Например, учитывая, что файл я получаю:

field1|field2|field3|f41|f5 
ield1|field2|field3|f42|f5 

Я думаю, что это не связано с тем, не существует «|» в конце строки. Есть ли способ сказать awk рассмотреть возврат каретки?

+1

Не совсем понятно, как ваш входной сигнал соответствует желаемому выходу. Не могли бы вы изменить свой пример, чтобы сделать его более понятным, добавив еще несколько объяснений? –

+0

какой персонаж исчезает? Я не вижу разницы между моим кодом и вашим на работе, у меня нет проблем, ни с добавлением | после некоторых строк в myfile.tx –

+0

awk всегда считает возврат каретки. так оно всегда работает с входным файлом. Трудно понять, что вам нужно –

ответ

3
  1. Не записывайте для петель с помощью какого-то дурацкого синтаксиса как for(i=0; ++i <= n;), как это только запутывает код (например, мы должны думать, если i будет 0 или 1 первый раз через этот цикл, поскольку это не ясно указано). Просто напишите их, поскольку они предназначены для написания for (init;condition;increment): for(i=1;i <= n;i++).
  2. Не перенаправлять входные данные в awk, например. awk < file 'script', просто позвольте awk открыть файл awk 'script' file, поэтому у вас всегда есть доступ к FILENAME в ваших скриптах.
  3. Не добавляйте ложные полуколоны на протяжении всего скрипта - это не C.
  4. Не печатайте жестко закодированный разделитель полей несколько раз, например. print $1"|"$2"|"$3"|"a[i]"|"$5, используйте OFS, как это было разработано: OFS="|";...;print $1,$2,$3,a[i],$5.
  5. Не используйте строки в контексте регулярного выражения, если у вас нет оснований для этого, поскольку они просто запутывают, усложняют и снижают эффективность кода, например. вместо split($4,a,";") вы должны использовать split($4,a,/;/).
  6. Используйте пробел/отступы, это удивительно дешево.

Так шаг 1, чтобы переписать сценарий:

awk < myfile.txt -F\| '{ 
n=split($4,a,";"); 
print $1 
for(i=0; ++i <= n;) 
print $1"|"$2"|"$3"|"a[i]"|"$5"|"; 
}' 

как:

awk ' 
BEGIN { FS=OFS="|" } 
{ 
    n=split($4,a,/;/) 
    print $1 
    for(i=1; i<=n; i++) 
     print $1, $2, $3, a[i], $5, "" 
} 
' myfile.txt 

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

$ awk ' 
BEGIN { FS=OFS="|" } 
{ 
    n=split($4,a,/;/) 
    for(i=1; i<=n; i++) 
     print $1, $2, $3, a[i], $5, "" 
} 
' myfile.txt 
field1|field2|field3|f41|f5| 
field1|field2|field3|f42|f5| 
field1|field2|field3|f41|f5| 
field1|field2|field3|f41|f5| 
field1|field2|field3|f42|f5| 
field1|field2|field3|f43|f5| 

Итак - это то, что вы хотели? К сожалению, вы использовали одни и те же значения для одних и тех же позиций поля во всех входных строках, поэтому мы не можем определить, какие выходные линии/поля поступают из входных строк/полей, и вы не опубликовали свой полный ожидаемый результат, поэтому мы не можем сказать если выше - ожидаемый результат или нет.Также неясно, действительно ли вы хотите всегда печатать пустое поле в конце каждой выходной строки или нет или действительно хотите жестко закодировать количество полей вывода.

О, и если символы исчезают в вашем выходе, это связано с тем, что в вашем входном файле есть управляющие символы или другие ложные управляющие символы. Используйте cat -v, чтобы увидеть их и dos2unix или аналогичные, чтобы удалить их, если они управляют.

+1

Спасибо за помощь, очень полезные советы! Во всяком случае, это все еще не решает мою проблему. Пожалуйста, проверьте мой добавленный пример. – Phate

+1

Решенный! Я забыл вызвать dos2unix! – Phate

1

Это будет работать для вас

awk -F"|" '{n=split($4,a,";"); for(i=1;i<=n;i++){ print $1FS$2FS$3FS a[i] FS $5}}' file.dat 
field1|field2|field3|f41|f5 
field1|field2|field3|f42|f5 
field1|field2|field3|f41|f5 
field1|field2|field3|f41|f5 
field1|field2|field3|f42|f5 
field1|field2|field3|f43|f5 
Смежные вопросы