Como passar a variável no padrão ao usar o comando sed?

0

Eu tenho o arquivo abc.sh

search_dir='dummy'
filename='numbers.txt'

for entry in "$search_dir"/*
do
  while read p;
  do 
    sed -i '' "/$p/d" $entry
  done < $filename
done

Tentando excluir uma linha com o padrão correspondente. Basicamente, o padrão é apenas uma string que estou passando do arquivo. Mas infelizmente, não está funcionando.

O que eu sou capaz de depurar é que eu não estou passando a variável de maneira correta.

EDITAR: numbers.txt

2018061300006178
2018061300006179
2018061300006325
2018061300006326
2018061400006505

o conteúdo dos arquivos que estão presentes em search_dir é:

1888~2018061400006505~0101~1~OWNED~SELF EMPLOYED~~~~3~~AGRICULTURE~~~OTHERS~AGRICULTURIST~~~AGRICULTURE~~~~~~~~N~N~Y~N~N~~300000-500000~~~49582E95361D5FA0C10C4C419B2940591C17E94EF329C31047A6B7DE26E68638
1889~2018061400006505~0101~2~OWNED~SELF EMPLOYED~~~~32~~AGRICULTURE~~~OTHERS~AGRIC

Portanto, o numbers.txt contém 2018061400006505 e o arquivo também contém dados relacionados a números, portanto, desejo excluir a linha que corresponde aos números fornecidos.

    
por Ankur_009 17.06.2018 / 19:41

1 resposta

4

Contanto que os números em seu exemplo não contenham o delimitador que sed está usando (por padrão / ), o $p em seu código será interpretado como uma expressão regular (com tudo o que isso significa ).

Seu código:

search_dir='dummy'
filename='numbers.txt'

for entry in "$search_dir"/*
do
  while read p;
  do 
    sed -i '' "/$p/d" $entry
  done < $filename
done

Aqui, você deseja excluir todas as linhas nos arquivos em $search_dir que contém qualquer um dos números em $filename . Se isso funciona ou não, depende de como seu sed trata -i '' . Com algumas implementações de sed , você teria que usar -i sem um argumento.

Relacionado a sed -i e portabilidade: Como posso conseguir portabilidade com sed -i (edição no local)?

É mais seguro gravar o resultado em um arquivo temporário e depois mover esse arquivo para o nome do arquivo original:

for entry in "$search_dir"/*
do
  while read p;
  do 
    sed "/$p/d" "$entry" >"$entry.tmp" && mv "$entry.tmp" "$entry"
  done <"$filename"
done

Isso garante que ele funcionará independentemente de com que sed implementação você está trabalhando. Em geral, é uma má idéia tentar fazer alterações locais nos arquivos durante o teste de um script, então você pode querer comentar que mv antes de estar satisfeito com a maneira como o script funciona.

Isso ainda é um pouco inseguro como uma solução geral, já que você está realmente "usando dados como código" (os números são dados e você os usa como parte do seu script sed ). Isso significa que você pode facilmente causar um erro de sintaxe no script sed apenas inserindo um / em um dos números no arquivo de números.

Como a operação é tão simples, podemos usar grep . Isso também elimina o loop while interno:

for entry in "$search_dir"/*
do
  grep -Fv -f "$filename" "$entry" >"$entry.tmp" && mv "$entry.tmp" "$entry"
done

Isso fará com que grep leia seus padrões de $filename e os aplique ao arquivo $entry . O -v significa que vamos descartar qualquer linha que contenha o padrão e -F significa grep não interpretará os números como expressões regulares, mas como sequências fixas. Com -f "$filename" , obtemos grep para ler as seqüências de caracteres de $filename .

Se houver diretórios em $search_dir , poderíamos ignorar estes:

for entry in "$search_dir"/*
do
  [ ! -f "$entry" ] && continue
  grep -Fv -f "$filename" "$entry" >"$entry.tmp" && mv "$entry.tmp" "$entry"
done

Outra maneira ainda mais segura de fazer sua operação é usar awk . Já que com as soluções sed e grep acima, o número é correspondido em qualquer lugar na linha, é concebível que possamos excluir as linhas erradas. Com awk , é fácil combinar apenas o segundo campo ~ -delimited nos dados:

for entry in "$search_dir"/*; do
    [ ! -f "$entry" ] && continue
    awk -F '~' 'NR==FNR { num[$0]; next } !($2 in num)' "$filename" "$entry" >"$entry.tmp" &&
    mv "$entry.tmp" "$entry"
done

O programa awk preenche primeiro um array / hash associativo com os números como chaves e, em seguida, imprime todas as linhas do arquivo $entry cuja segunda coluna ~ -delimited não é uma chave nesse hash.

    
por 17.06.2018 / 20:09