2016-01-27 2 views
0

У меня есть разделенный запятыми файл, и мне нужно, чтобы извлечь третье поле из каждого test.txt line.File имеет следующее содержание:Как игнорировать пробелы и запятые при чтении из файла

6,STRING TO DECIMAL WITHOUT DEFAULT,cast($src_fld as DECIMAL(15,2) $tgt_fld 
7,STRING TO INTERGER WITHOUT DEFAULT,cast($src_fld as integer) $tgt_fld     
10,DEFAULT NO RULE,'$default' $tgt_fld 

кошка test.txt | AWK -F «{печати $ 3}»

если я пишу выше команды, я получаю неправильный вывод, как:

> cast($src_fld as DECIMAL(15 
> cast($src_fld as integer) $tgt_fld 
> '$default' $tgt_fld 

Может кто-нибудь пожалуйста, скажите мне, как достичь it.I нужно написать это в цикле, чтобы дальнейшая обработка могла быть выполнена позже. Обратите внимание, что каждое третье поле может содержать пробел и запятую (,).

+0

Я не понимаю. 'awk' делает цикл по файлу за строкой? – pfnuesel

+0

Я уже редактировал свой вопрос с правильным выходом. – user1768029

+0

Нет, вы этого не сделали. Все вопросы показывают, что вы получаете то, что вы НЕ хотите, а не то, что вы хотите. –

ответ

2

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

$ cut -d ',' -f 3- test.txt 
cast($src_fld as DECIMAL(15,2) $tgt_fld 
cast($src_fld as integer) $tgt_fld     
'$default' $tgt_fld 
+0

Спасибо за ваш ответ. Можете ли вы также рассказать мне, как использовать эту команду в цикле for. Потому что мне нужно обработать третье поле позже после его извлечения. Если я пишу его как *** для i в 'cut -d ',' -f 3- test.txt', do echo $ i; done; ***, он не обеспечивает надлежащего вывода. – user1768029

+1

@ user1768029 Вы можете сделать 'while IFS = read -r line; do echo $ line; done <<(cut -d ',' -f 3- test.txt) ', чтобы перебрать его, но в зависимости от того, что вы хотите сделать, это может быть не идеально. –

+1

@ user1768029, [не читайте строки с for] (http://mywiki.wooledge.org/DontReadLinesWithFor) –

1

Если в первых двух полях есть запятая, ваша задача невозможна.

1,second,field,with,commas,third,field,with,commas 

У вас нет способа узнать, где заканчивается второе поле и начинается третье поле.

Вам действительно нужно использовать фактический синтаксис CSV и проанализировать файл с помощью синтаксического анализатора CSV.

1,"second,field,with,commas","third,field,with,commas" 

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

sed 's/^[^,]\+,[^,]\+,//' file 
+0

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

+0

Удаляет первые два поля, разделенные запятыми, оставляя только третье. '[^,] \ +' - один или несколько символов не запятой. –

2

awk на помощь!

не общее решение, но работает для формата

$ awk -F, '{for(i=4;i<=NF;i++) $3 = $3 FS $i} {print $3}' badcsv 

cast($src_fld as DECIMAL(15,2) $tgt_fld 
cast($src_fld as integer) $tgt_fld 
'$default' $tgt_fld 

Объяснение Вы печати часть текста после 2-го поля на основе FS = «». Сценарий добавляет остальные поля в $ 3 перед печатью.

+0

Не могли бы вы объяснить, как это работает? – user1768029

0

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

$ cat tst.awk 
BEGIN { FS="," } 
{ 
    $0 = gensub(/([(][^()]+),([^()]+[)])/,"\\1"RS"\\2","g",$0) 
    for (i=1; i<=NF; i++) { 
     gsub(RS,FS,$i) 
     print NR, NF, i, $i 
    } 
    print "----" 
} 

$ awk -f tst.awk file 
1 3 1 6 
1 3 2 STRING TO DECIMAL WITHOUT DEFAULT 
1 3 3 cast($src_fld as DECIMAL(15,2) $tgt_fld 
---- 
2 3 1 7 
2 3 2 STRING TO INTERGER WITHOUT DEFAULT 
2 3 3 cast($src_fld as integer) $tgt_fld 
---- 
3 3 1 10 
3 3 2 DEFAULT NO RULE 
3 3 3 '$default' $tgt_fld 
---- 

выше использует GNU awk для gensub(), с другими awks используйте match() + substr().

0

Если вы хотите использовать цикл, вы можете использовать

while IFS=, read -r field1 field2 rest_of_line; do 
    echo "Field 3: ${rest_of_line}" 
done < test.txt