С регулярными выражениями в математическом смысле это возможно, но размер регулярных выражений растет экспоненциально относительно размера алфавита, таким образом, это не практично.
Существует простой путь с отрицанием и обратными ссылками.
grep '[spine]' | grep -Ev '([spine]).*\1'
Первое grep
выбирает строки, которые содержат по крайней мере один из einps
; второе grep
строки отклонений, которые содержат больше чем одного из любого (например, разрешение spinal tap
и spend
но нет foobar
или see
).
Кроме того, как сократить и перестроить поля (охваченный в других ответах), существует проблема изворотливых полей CSV.
Если Ваши данные попадают в эту "изворотливую" категорию, немного пред, и фильтрация сообщения может заботиться о нем. Фильтры, показанные ниже, требуют символов \x01
,\x02
,\x03
,\x04
не появиться где угодно в Ваших данных.
Вот фильтры, перенес простое awk
полевой дамп.
Поле Примечание: пять имеет недопустимое/неполное "заключенное в кавычки поле" расположение, но это мягко в конце строки (в зависимости от синтаксического анализатора CSV). Но, конечно, это вызвало бы проблематичные результаты unexpedted, если бы это должно было быть подкачано далеко от его текущего положения конца строки.
Обновление; 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
время: \{1\}
):
$ sed 's/\(\([^,]\+,\)\{1\}\)[^,]\+,\(.*\)/\1\3/' /path/to/your/file
Существует много способов выполнить в этом awk
, ни один из них особенно изящный. Можно использовать a 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
для цикла путем это было бы что-то как (снова игнорирование запаздывающей запятой):
$ 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
может отформатировать вывод также.
BEGIN { FS=","; OFS=","; }
.
–
16.12.2011, 04:13
Учитывая разграниченный пространством файл в следующем формате:
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
, но это, кажется, производит разделенный пробелом, даже если разделитель полей ,
(разделитель полей просто управляет, как он обрабатывает вход)
– Michael Mrozek♦
16.12.2011, 04:59
Это будет работать для удаления ввода
awk '{$2="";$0=$0;$1=$1}1'
ввода
a b c d
a c d