Como uso nomes de arquivos em um comando sed?

5

Eu tenho um número de arquivos .conf que são idênticos e estão no mesmo diretório, com a exceção de ter nomes de arquivo diferentes. Em cada arquivo .conf com nome exclusivo, gostaria de substituir um conjunto de caracteres no arquivo pelo nome do arquivo. Por exemplo:

Atualmente em todos os arquivos:

datafname = example.nex
ofprefix = best.example

Saída ideal:

Nome do arquivo: 25.conf

datafname = 25.nex
ofprefix = best.25

Nome do arquivo: 26.conf

datafname = 26.nex
ofprefix = best.26

Eu pensei que eu poderia usar sed para percorrer todos esses arquivos para encontrar e substituir a seqüência de texto com o nome do arquivo usando algo como:

sed -i conf 's/example/echo $f/g' *

mas isso não está funcionando corretamente. Alguém teria alguma sugestão sobre como fazer isso?

    
por foolsparadise 04.03.2018 / 18:04

4 respostas

7

Você pode fazer:

for f in *.conf; do
    base=$(basename "$f" '.conf') # gives '25' from '25.conf'
    sed -i.before "s/example/$base/g" "$f"
done

Ao usar a opção -i para sed , você deve ter certeza absoluta de que o comando sed funciona porque -i altera os arquivos no local . Isso significa que a saída gerada irá sobrescrever o arquivo de entrada. Se o seu comando de substituição ( s/…/…/ ) estiver errado, você pode acabar com arquivos vazios e sem backups. Por isso, usei -i.before , o que deixará um arquivo *.before com o conteúdo original.

    
por PerlDuck 04.03.2018 / 18:25
5

Você pode usar um loop for para iterar os arquivos. Use a expansão de parâmetro para remover a extensão do arquivo. Use aspas duplas em torno da expressão, caso contrário, a variável não seria expandida.

#! /bin/bash
for f in *.conf ; do
    b=${f%.conf}
    sed -i "s/example/$b/" "$f"
done
    
por choroba 04.03.2018 / 18:23
2

Você pode fazer a tarefa sem um loop usando o GNU parallel :

parallel sed -i.old s/example/{.}/ {} ::: *.conf

Isso é especialmente útil se você tiver um lote de arquivos para editar, já que parallel executa um trabalho por núcleo de CPU.

  • -i.old significa: edite o arquivo i n-place e faça um backup adicionando a extensão .old ao nome do arquivo original (remova .old se você não quiser um backup, mas lembre-se de que você não tem um backup então)
  • s/example/{.}/g significa s ubstitute example com o nome do arquivo de entrada sem sua extensão ( {.} ) e% g lobally (= para todas as ocorrências)
  • {} é substituído pelo nome do arquivo de entrada
  • ::: separa o comando para ser executado a partir dos argumentos para passar para ele
  • *.conf corresponde a cada arquivo .conf no diretório atual
por dessert 05.03.2018 / 11:07
1

Com o awk, que tem uma variável FILENAME definida automaticamente para o nome do arquivo (e, se o GNU awk, também com edições no local):

$ for i in {20..26}; do printf "%s\n" "datafname = example.nex" "ofprefix = best.example" > $i.conf; done
$ gawk -i inplace 'FNR == 1 {split(FILENAME, file, ".")} {gsub("example", file[1])} 1' *.conf
$ cat 25.conf
datafname = 25.nex
ofprefix = best.25
  • FNR == 1 {split(FILENAME, file, ".")} : na primeira linha de cada arquivo, divida o nome do arquivo em . e armazene-o no file array
  • {gsub("example", file[1])} 1 : para todas as linhas, substitua example pelo primeiro elemento da matriz file e imprima.
por muru 05.03.2018 / 02:47