Удалить несколько строк в CSV-файле

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

delete() {
  awk -F "\"*;\"*" '$1 != '$@' {print $ALL}' input.csv > output.csv
}

delete $@

Однако теперь мне нужно удалить несколько клиентов одновременно. Я могу идентифицировать клиента по его номеру, который хранится в первом столбце файла CSV. Я должен создать массив для разных номеров клиентов и создать цикл while для циклического прохождения по массиву, но я не могу этого понять.

1
задан 27 June 2018 в 20:04

2 ответа

Я не уверен, почему Вы переносите это в функцию оболочки - я предположу, что это - требование Вашего присвоения.

Во-первых, отметьте то использование "*;"* поскольку разделитель полей в Awk не является устойчивым способом обработать заключенные в кавычки поля CSV - он перестанет работать, например, если или первое поле или продлится, поле на строке заключается в кавычки, и он не сохранит заключенные в кавычки разделители (т.е. заключенные в кавычки поля, которые на самом деле содержат a ;) который пропускает смысл заключения в кавычки полей CSV.

Во-вторых, Вы не должны пытаться передать переменные оболочки (или позиционные параметры) в выражение Awk тот путь - корректный путь состоит в том, чтобы или экспортировать их и затем получить доступ к ним через ENVIRON массив или параметр командной строки использования -v. Таким образом, Ваш "единственный клиент" реализация был бы лучше записан

delcust() {
  awk -F '"*;"*' -v cust="$1" '$1 != cust' input.csv > output.csv
}
delcust "$1"

В то время как Вы могли изменить это для передачи нескольких позиционных параметров, я предложу передать список клиентов через стандартный вход и проанализировать его как файл значений; тем путем можно сделать канонический поиск Awk на основе ассоциативного массива (или хеш):

delcusts() {
  printf '%s\n' "$@" | awk -F'"*;"*' 'NR==FNR {custs[$0]=1; next} !($1 in custs)' - input.csv > output.csv
}
delcusts "$@"

Обратите внимание, что Вам не нужно явное print в Awk с тех пор print действие по умолчанию, если правило оценивает ненулевой.

2
ответ дан 27 June 2018 в 20:04

В действительности нет необходимости в массиве. Вы можете определить свою функцию следующим образом:

delete() {
  awk -v customer="^($1)\$" -F ";" '$1 !~ customer {print $ALL}' input.csv >output.csv 
}

Я не понял, как вы определили разделитель полей, поэтому я изменил его, чтобы иметь возможность проверять. Соответствующей частью является использование отрицательного регулярного выражения !~. Также я использовал параметр -v для awk, который может избавить вас от головной боли при цитировании оболочки.

При этом вы можете использовать такой параметр для удаления нескольких клиентов:

delete 'bla|foo'

Для в input.csv вот так:

bla;blu;bli
foo;faa;fii
blafoo;blufaa;blifii

это приведет к

[ 113]

в output.csv.

Если вы действительно хотите использовать массив, вы можете дополнительно определить небольшую вспомогательную функцию, которая подготавливает массив для использования с функцией delete(), описанной выше:

join() { local IFS=\|; echo "$*"; }

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

$ a=(bla blu)
$ join ${a[@]}
bla|blu

Тогда вы можете вызвать delete() так:

$ a=(customer1 customer2)
$ delete "$(join ${a[@]})"

(Небольшое примечание для пользователей zsh: join() ] функция не нужна для zsh, вы можете просто использовать следующее расширение параметра: ${(j:|:)a}, чтобы объединить все элементы массива с символом |)

0
ответ дан 27 June 2018 в 20:04

Другие вопросы по тегам:

Похожие вопросы: