Я работаю над этим заданием, чтобы удалить строки из файла CSV с разными клиентами. Я выяснил, как удалить одного конкретного клиента, используя этот код:
delete() {
awk -F "\"*;\"*" '$1 != '$@' {print $ALL}' input.csv > output.csv
}
delete $@
Однако теперь мне нужно удалить несколько клиентов одновременно. Я могу идентифицировать клиента по его номеру, который хранится в первом столбце файла CSV. Я должен создать массив для разных номеров клиентов и создать цикл while для циклического прохождения по массиву, но я не могу этого понять.
Я не уверен, почему Вы переносите это в функцию оболочки - я предположу, что это - требование Вашего присвоения.
Во-первых, отметьте то использование "*;"*
поскольку разделитель полей в 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
действие по умолчанию, если правило оценивает ненулевой.
В действительности нет необходимости в массиве. Вы можете определить свою функцию следующим образом:
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}
, чтобы объединить все элементы массива с символом |
)