Как я могу сделать следующее для файла CSV с помощью sed
или awk
?
- Удалить столбец
- Дублировать столбец
- Переместить столбец
У меня есть большая таблица с более чем 200 строками, и я не очень знаком с ней sed
.
Как я могу сделать следующее для файла CSV с помощью sed
или awk
?
У меня есть большая таблица с более чем 200 строками, и я не очень знаком с ней sed
.
Ответы:
Помимо того, как вырезать и переупорядочивать поля (описанные в других ответах), существует проблема необычных полей CSV.
Если ваши данные попадают в эту «причудливую» категорию, об этом может позаботиться небольшая часть предварительной и последующей фильтрации. Фильтры , указанные ниже , требуют символы \x01
, \x02
, \x03
, \x04
чтобы не появляться в любом месте в ваших данных.
Вот фильтры, обернутые вокруг простого awk
дампа поля.
Примечание: field-Five имеет недопустимый / неполный макет «заключенного в кавычки», но он доброкачествен в конце строки (в зависимости от синтаксического анализатора CSV). Но, конечно, это приведет к проблематичным неисследованным результатам, если его поменять с текущей позиции в конце строки .
Обновить; user121196 указал на ошибку, когда запятая предшествует завершающей кавычке. Вот исправление.
Данные
cat <<'EOF' >file
field one,"fie,ld,two",field"three","field,\",four","field,five
"15111 N. Hayden Rd., Ste 160,",""
EOF
Код
sed -r 's/^/,/; s/\\"/\x01/g; s/,"([^"]*)"/,\x02\1\x03/g; s/,"/,\x02/; :MC; s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g; tMC; s/^,// ' file |
awk -F, '{ for(i=1; i<=NF; i++) printf "%s\n", $i; print NL}' |
sed -r 's/\x01/\\"/g; s/(\x02|\x03)/"/g; s/\x04/,/g'
Выход:
field one
"fie,ld,two"
field"three"
"field,\",four"
"field,five
"15111 N. Hayden Rd., Ste 160,"
""
Вот предварительный фильтр , дополненный комментариями. Постфильтр только разворот . , ,\x01
\x02
\x03
\x04
sed -r '
s/^/,/ # add a leading comma delimiter
s/\\"/\x01/g # obfuscate escaped quotation-mark (\")
s/,"([^"]*)"/,\x02\1\x03/g # obfuscate quotation-marks
s/,"/,\x02/ # when no trailing quote on last field
:MC # obfuscate commas embedded in quotes
s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g
tMC
s/^,// # remove spurious leading delimiter
'
Это зависит от того, использует ли ваш CSV-файл запятые только для разделителей, или если у вас есть сумасшествие, подобное:
поле одно, "поле, два", поле три
Это предполагает, что вы используете простой файл CSV:
Вы можете избавиться от одного столбца многими способами; Я использовал столбец 2 в качестве примера. Возможно, проще всего использовать этот метод cut
, который позволяет вам указать разделитель -d
и какие поля вы хотите напечатать -f
; это говорит о том, что нужно разделить запятые и выходные поля 1 и поля 3 до конца:
$ cut -d, -f1,3- /path/to/your/file
Если вам действительно нужно использовать sed
, вы можете написать регулярное выражение, которое совпадает с первыми n-1
полями, n
полем th и остальными, и пропустить вывод n
th (здесь n
2, поэтому первая группа соответствует 1
time :) \{1\}
:
$ sed 's/\(\([^,]\+,\)\{1\}\)[^,]\+,\(.*\)/\1\3/' /path/to/your/file
Есть несколько способов сделать это awk
, но ни один из них не особенно элегантен. Вы можете использовать for
цикл, но иметь дело с конечной запятой - боль; игнорируя, что это будет что-то вроде:
$ awk -F, '{for(i=1; i<=NF; i++) if(i != 2) printf "%s,", $i; print NL}' /path/to/your/file
Мне легче вывести поле 1, а затем использовать, substr
чтобы вывести все после поля 2:
$ awk -F, '{print $1 "," substr($0, length($1)+length($2)+3)}' /path/to/your/file
Это раздражает для колонок дальше, хотя
В sed
сущности это то же самое выражение, что и раньше, но вы также захватываете целевой столбец и включаете эту группу несколько раз в замену:
$ sed 's/\(\([^,]\+,\)\{1\}\)\([^,]\+,\)\(.*\)/\1\3\3\4/' /path/to/your/file
В awk
цикле for это будет что-то вроде (опять же игнорируя запятую):
$ awk -F, '{
for(i=1; i<=NF; i++) {
if(i == 2) printf "%s,", $i;
printf "%s,", $i
}
print NL
}' /path/to/your/file
substr
Образом:
$ awk -F, '{print $1 "," $2 "," substr($0, length($1)+2)}' /path/to/your/file
(tcdyl предложил лучший метод в своем ответе )
Я думаю, что sed
решение естественно следует из других, но оно начинает смехотворно долго
awk
это ваша лучшая ставка. awk
печатает поля по номеру, так что ...
awk 'BEGIN { FS=","; OFS=","; } {print $1,$2,$3}' file
Чтобы удалить столбец, не печатайте его:
awk 'BEGIN { FS=","; OFS=","; } {print $1,$3}' file
Чтобы изменить порядок:
awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file
Перенаправить на выходной файл.
awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file > output.file
awk
Можно также отформатировать вывод.
Дан файл с разделителями пробелами в следующем формате:
1 2 3 4 5
Вы можете удалить поле 2 с помощью awk следующим образом:
awk '{ sub($2,""); print}' file
который возвращается
1 3 4 5
Замените столбец 2 на столбец n, где это необходимо.
Чтобы дублировать столбец 2,
awk '{ col = $2 " " $2; $2 = col; print }' file
который возвращается
1 2 2 3 4 5
Чтобы переключить столбцы 2 и 3,
awk '{temp = $2; $2 = $3; $3 = temp; print}'
который возвращается
1 3 2 4 5
Как правило, awk хорошо разбирается в понятии полей . Если вы имеете дело с CSV, а не с пробелом, вы можете просто использовать
awk -F,
чтобы определить ваше поле как запятую, а не пробел (который по умолчанию). В Интернете есть несколько хороших ресурсов awk, один из которых я перечислю в качестве источника ниже.
Источник для № 3
awk
, но, похоже, он выводит разделенный пробелами, даже если разделитель полей (разделитель ,
полей просто контролирует, как он обрабатывает ввод)
Это будет работать для удаления
awk '{$2="";$0=$0;$1=$1}1'
вход
a b c d
Выход
a c d