IFS отделяет строку типа "Hello","World","this","is, скучная", "line"
Я пытаюсь разобрать файл.csv, и у меня есть некоторые проблемы с IFS. Файл содержит такие строки:
"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"
3 ответа
Попробуй:
sed 's/","/"\n"/g' <<<"${line}"
sed
имеет команду поиска и замены s
который использует регулярное выражение для поиска шаблона.
Регулярное выражение заменяет ,
в ","
с новой строкой чар.
Как следствие, каждый элемент находится на отдельной строке.
Вы можете использовать тараканы с FPAT
чтобы определить, что делает правильную строку -
Вход:
"Привет","мир","это, является"
Сценарий:
gawk -n 'BEGIN{FS=",";OFS="\n";FPAT="([^,]+)|(\"[^\"]+\")"}{$1=$1;print $0}' somefile.csv
Выход:
"Привет"
"Мир"
"это"
Башлиб обеспечивает csvline
функция. Предполагая, что вы установили его где-то в вашем PATH:
line='"Hello","World","this","is, a boring","line"'
source bashlib
csvline <<<"$line"
printf '%s\n' "${CSVLINE[@]}"
... вывод из вышеперечисленного:
Hello
World
this
is, a boring
line
Чтобы процитировать реализацию (авторское право lhunath, текст ниже взят из этой конкретной ревизии соответствующего git-репо):
# _______________________________________________________________________
# |__ 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" ) ||:
} # _____________________________________________________________________