Existem alguns problemas com o código e o arquivo de entrada nesta pergunta:
-
O arquivo de entrada obviamente tem retornos de carro à direita ( \r
) em cada linha. Provavelmente, isso deve ter sido criado em uma máquina Windows como um arquivo de texto do DOS. A maneira usual de se livrar desses retornos de carro é executar dos2unix
no arquivo. Veja, por exemplo, a pergunta What é '^ M' e como posso me livrar disso?
-
Todas as expansões variáveis devem ser duplamente citadas. Em seu comando, você usa $f2
sem aspas como um nome de caminho para um diretório. Isso falharia se $f2
contivesse espaços.
-
As aspas simples impedem que o shell expanda uma variável, o que significa que o script sed
está procurando por linhas que correspondam à expressão regular literal $f1
. Essa expressão regular nunca corresponderá, pois o $
corresponderá apenas ao final de uma linha e não haverá linha que termine e, em seguida, contenha os caracteres f1
na mesma linha . Duplicar o script de edição sed
fará com que o shell expanda a variável $f1
antes de invocar sed
.
-
O padrão vcs*.pv
deve ser um argumento para a opção -name
de find
, mas como não é citada, ele se expande para qualquer nome no diretório atual que corresponda a esse padrão de globbing. Portanto, se você tivesse um arquivo no diretório atual cujo nome fosse vcs-test.pv
, find
seria invocado com -name vcs-test.pv
e você só encontraria arquivos com esse nome. Se você tivesse vários nomes correspondentes no diretório atual, você faria com que find
reclamasse sobre opções desconhecidas.
-
O arquivo export.csv
é enviado para (e esvaziado antes que qualquer saída do loop aconteça). Você gostaria que o loop fosse lido a partir dele. Isso envolve alterar >
para <
.
O script corrigido:
while IFS=',' read f1 f2; do
find "$f2" -type f -name 'vcs*.pv' -exec sed -i "/$f1/d" {} +
done <export.csv
Também adicionei -type f
à linha de comando find
, pois provavelmente não queremos que os nomes de diretório sejam pegos acidentalmente. Eu também fiz isso para que a variável IFS
seja definida somente para o comando read
.
Esta é uma variação do acima, no caso de todos os arquivos estarem diretamente abaixo do diretório principal cujo nome você está lendo no arquivo CSV:
while IFS=',' read dir pattern; do
for name in "$dir"/vcs*.pv; do
test -f "$name" && sed -i "s/$pattern/d" "$name"
done
done <export.csv
O bom disso é que você se livra de find
. O ruim é que agora você tem uma invocação de sed
por arquivo (geralmente não é um problema, a menos que você tenha centenas ou mais arquivos).
A seguir, uma variação acima, que exclui linhas dependendo da string lida no arquivo CSV. A diferença é que os trechos de código, acima de tudo, interpretam o padrão como uma expressão regular , não como uma string fixa. Isso é importante se a string contiver caracteres interpretados como "especiais" em uma expressão regular, como .
, *
, [
, ]
etc.
while IFS=',' read dir string; do
for name in "$dir"/vcs*.pv; do
[ ! -f "$name" ] && continue
grep -v -F -e "$string" "$name" >"$name.tmp" && mv -f "$name.tmp" "$name"
done
done <export.csv