Вопрос или проблема
Я пытаюсь отфильтровать строки в CSV файле на основе двух конкретных условий, используя awk:
- Поле 2 должно быть пустым и Поле 4 должно быть непустым.
- Поле 2 должно быть непустым и Поле 4 должно быть пустым.
Например, рассмотрим файл CSV со следующим содержимым:
"venBio","http://www.venbio.com","","venBio является инвестором, расположенным в Соединенных Штатах, Северная Америка."
"zhenZhou","http://www.zhenzhou.com","",""
"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"
Я хочу, чтобы скрипт awk сначала выводил:
"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"
а затем
"zhenZhou","http://www.zhenzhou.com","",""
Я пробовал различные подходы, но не смог правильно отфильтровать данные по этим условиям. Может ли кто-нибудь подсказать мне правильный синтаксис awk для достижения этого?
Попробованные подходы:
awk -F, '($2 == "" && $4 != "")' input.csv
awk -F, '($2 != "" && $4 == "")' input.csv
awk -F, '($2 ~ /^[[:space:]]*$/ && $4 !~ /^[[:space:]]*$/)' input.csv
awk -F, '($2 !~ /^[[:space:]]*$/ && $4 ~ /^[[:space:]]*$/)' input.csv
Вы можете использовать этот awk
:
awk -F, -v nul="""" '$2 != nul && $4 == nul {s = s $0 ORS}
$2 == nul && $4 != nul; END {printf "%s", s}' file
"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"
"zhenZhou","http://www.zhenzhou.com","",""
Предположения:
- все поля обернуты в двойные кавычки
- в полях нет встроенных/экранированных двойных кавычек
Если мы используем -F'"'
для обозначения разделителя полей ввода, то нам просто нужно помнить, что все поля данных на самом деле являются четными номерами (то есть 1-е поле ссылается на $2
, 2-е поле ссылается на $4
).
Изменяя и комбинируя первые два скрипта awk
автора вопроса:
awk -F'"' '
FNR==NR { if ($4 == "" && $8 != "") print; next } # обработка 1-го файла
{ if ($4 != "" && $8 == "") print } # обработка 2-го файла
' input.csv input.csv
ЗАМЕТКИ:
$4
— это 2-е поле данных;$8
— это 4-е поле данныхprint
без аргументов рассматривается так же, какprint $0
(то есть выводит всю строку как есть)- мы предоставляем две ссылки на входной файл (
input.csv
), чтобы ограничить использование памяти при генерации выходных данных в нужном порядке
Это генерирует:
"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"
"zhenZhou","http://www.zhenzhou.com","",""
Проблема с командами, которые вы пробовали, заключается в том, что awk не игнорирует двойные кавычки внутри каждого поля. Вы можете использовать аргумент разделителя для решения этой проблемы:
awk -F'","' '($2 == "" && $4 != "\"") || ($2 != "" && $4 == "\"")' file.csv
Поскольку поле $4
является последним, вам все равно нужно учесть эту последнюю двойную кавычку.
The One True Awk поддерживает CSV напрямую, но XOR все еще должен быть реализован как NOT/AND/OR:
awk --csv '(!length($2)&&length($4)) || (length($2)&&!length($4))' input.csv
в результате чего:
"zhenZhou","http://www.zhenzhou.com","",""
"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"
Если вы действительно хотите, чтобы результат был в порядке из вопроса, вы можете выполнить команду дважды:
awk --csv '!length($2)&&length($4)' input.csv
awk --csv 'length($2)&&!length($4)' input.csv
в результате чего:
"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"
"zhenZhou","http://www.zhenzhou.com","",""
Ответ или решение
Для решения вашей задачи по фильтрации строк в CSV-файле с использованием утилиты awk
, мы можем использовать следующую стратегию. Задача заключается в том, чтобы отфильтровать строки по двум условиям:
- Поле 2 должно быть пустым (null), а поле 4 — непустым (non-null).
- Поле 2 должно быть непустым (non-null), а поле 4 — пустым (null).
Мы будем использовать awk
с заданным разделителем. Поскольку в вашем случае поля заключены в кавычки, логично будет использовать awk
с указанием разделителя -F'"'
.
Пример использования awk
, чтобы отфильтровать необходимое количество строк:
awk -F'","' '
{
if ($2 == "" && $4 != "\"") {
print $0
}
}
' input.csv
awk -F'","' '
{
if ($2 != "" && $4 == "\"") {
print $0
}
}
' input.csv
Однако вышеупомянутый метод работает всего лишь для одного условия одновременно. Чтобы получить вывод в нужном порядке, необходимо выполнить обе команды подряд.
Таким образом, полная последовательность команд будет выглядеть так:
awk -F'","' '
{
if ($2 == "" && $4 != "\"") {
print $0
}
}
' input.csv
awk -F'","' '
{
if ($2 != "" && $4 == "\"") {
print $0
}
}
' input.csv
Объяснение:
-F'","'
: указывает, что поля отделены не только запятой, но и кавычками, что позволяет корректно обрабатывать строки.if ($2 == "" && $4 != "\"")
: проверяет первое условие, где поле 2 пусто, а поле 4 заполнено.if ($2 != "" && $4 == "\"")
: проверяет второе условие, где поле 2 заполнено, а поле 4 пусто.print $0
: выводит всю строку.
После выполнения данной последовательности вы получите следующий вывод:
"Loren","","","A famous Hollywood actress from the 1950s and 1960s"
"zhenZhou","http://www.zhenzhou.com","",""
Таким образом, используя указанные команды awk
, вы сможете эффективно фильтровать строки в вашем CSV-файле на основании заданных условий. Если у вас есть дополнительные вопросы по данной теме, не стесняйтесь обращаться!