2016-04-30 3 views
-1

Я пытаюсь разобрать CSV-файл, и у меня есть некоторые проблемы с IFS. Файл содержит такие строки:IFS выделяет строку типа «Hello», «World», «this», «is, boring», «line»

"Hello","World","this","is, a boring","line" 

Столбцы разделены запятой, поэтому я попытался взорвать строку с этим кодом:

IFS=, read -r -a tempArr <<< "$line" 

Но я получаю этот выход:

"Hello" 
"World" 
"this" 
"is 
a boring" 
"line" 

Я понимаю, почему, поэтому я пробовал некоторые другие команды, но я не получаю ожидаемого результата.

IFS=\",\" 
IFS=\", 
IFS=',\"' 
IFS=,\" 

Каждый раз, когда третий элемент разделен на 2 части. Как я могу использовать IFS для разделения строки на 5 частей?

"Hello" 
"World" 
"this" 
"is, a boring" 
"line" 
+4

'IFS' не предназначен для синтаксического анализа CSV-файлы; он может обрабатывать только простое разделение, которое не зависит от того, цитируется ли разделитель. Используйте язык, на котором * * имеет доступ к парсеру CSV. – chepner

+0

Я уверен, что это можно было бы теоретически * сделать в bash. И это не должно быть так сложно. –

+0

Не в чистом BASH, но, вероятно, gnu awk – anubhava

ответ

0

дать этому попытку:

sed 's/","/"\n"/g' <<<"${line}" 

sed имеет поиск и команда s которая использует регулярное выражение для поиска шаблона замены.

Регулярное выражение заменяет , на "," с новым символом линии.

Как следствие, каждый элемент находится на отдельной линии.

0

Вы можете использовать простак с FPAT, чтобы определить, что делает правильную строку -

Input:

"привет", "мир", "это, является"

Script:

gawk -n 'BEGIN{FS=",";OFS="\n";FPAT="([^,]+)|(\"[^\"]+\")"}{$1=$1;print $0}' somefile.csv 

Выход:

"привет"
"мир"
"это, является"

0

bashlib обеспечивает csvline функцию. Предполагая, что вы установили его где-то в своем ПУТЕ:

line='"Hello","World","this","is, a boring","line"' 

source bashlib 
csvline <<<"$line" 
printf '%s\n' "${CSVLINE[@]}" 

...Выход из вышеприведенных существ:

Hello 
World 
this 
is, a boring 
line 

Цитируют реализации (что авторское право lhunath, приведенный ниже текст взят от this specific revision of the relevant git repo):

# _______________________________________________________________________ 
# |__ csvline ____________________________________________________________| 
# 
#  csvline [-d delimiter] [-D line-delimiter] 
# 
# Parse a CSV record from standard input, storing the fields in the CSVLINE array. 
# 
# By default, a single line of input is read and parsed into comma-delimited fields. 
# Fields can optionally contain double-quoted data, including field delimiters. 
# 
# A different field delimiter can be specified using -d. You can use -D 
# to change the definition of a "record" (eg. to support NULL-delimited records). 
# 
csvline() { 
    CSVLINE=() 
    local line field quoted=0 delimiter=, lineDelimiter=$'\n' c 
    local OPTIND=1 arg 
    while getopts :d: arg; do 
     case $arg in 
      d) delimiter=$OPTARG ;; 
     esac 
    done 

    IFS= read -d "$lineDelimiter" -r line || return 
    while IFS= read -rn1 c; do 
     case $c in 
      \") 
       ((quoted = !quoted)) 
       continue ;; 
      $delimiter) 
       if ((! quoted)); then 
        CSVLINE+=("$field") field= 
        continue 
       fi ;; 
     esac 
     field+=$c 
    done <<< "$line" 
    [[ $field ]] && CSVLINE+=("$field") ||: 
} # _____________________________________________________________________