for file in f1 f2; do
sed -i '8s/^.*$/foo/' "$file"
done
Suponha que eu tenha dez scripts de shell bash: script1.sh
, script2.sh
, ..., script10.sh
. Inicialmente, todos os dez arquivos são idênticos.
Agora, gostaria de fazer duas alterações em cada script:
Em cada arquivo, gostaria de alterar uma linha específica (digamos, a linha 8) - ou seja, excluir o que está na linha 8 e substituí-la por uma string "constante" que eu especifico, como "This is line 8."
Isso é semelhante a esta pergunta , mas lá eles queriam substituir "AAA"
por "BBB"
, enquanto eu gostaria de substituir a linha 8 (o que quer que seja) por "This is line 8."
.
Em cada arquivo, gostaria de alterar outra linha específica (digamos, linha 21) e substituí-la por uma sequência "variável" que especifico. Por exemplo, em script1.sh
, quero alterar a linha 21 para "XYZ"
; em script2.sh
eu quero mudar a linha 21 para "PQR"
; e em script3.sh
eu quero mudar a linha 21 para "ABC"
. Essencialmente, isso é apenas muitas chamadas para a função em (1) acima - exceto que eu estaria fazendo a alteração em um arquivo individual em vez de em todos os arquivos, e especificando dez cadeias diferentes do que apenas um. Então, para obter (2) aqui, talvez eu apenas chame (1) dez vezes diferentes com parâmetros diferentes.
Estou interessado em soluções que usem programas Linux normalmente disponíveis como bash
, vi
, awk
, gawk
, etc.
Usando o awk
for file in script1.sh script2.sh script3.sh ... script10.sh; do
temp=$(mktemp)
awk '
BEGIN {
line8 = "This is line 8"
line21["script1.sh"] = "XYZ"
line21["script2.sh"] = "PQR"
line21["script3.sh"] = "ABC"
# ...
}
FNR == 8 { print line8; next }
FNR == 21 && FILENAME in line21 { print line21[FILENAME]; next }
{print}
' "$file" > "$temp" && mv "$temp" "$file"
done
ou, usando bash e sed
# bash variables to store new values. requires bash v4 for the associative array
line8="This is line 8"
declare -A line21=(
[script1.sh]="XYZ"
[script2.sh]="PQR"
[script3.sh]="ABC"
# ...
)
# then use sed
for file in script1.sh script2.sh script3.sh ... script10.sh; do
sed -i "8s/.*/$line8/; 21s/.*/${line21[$file]}/" "$file"
done
Com a solução sed, você precisa ter cuidado para que as novas linhas não contenham "/" caracteres,
como isso vai quebrar o comando s///
. Embora você possa usar diferentes
caracteres delimitadores, como s|pattern|replacement|
(nesse caso, o
mesmo aviso aplica-se, recursivamente)
ed
também funciona:
for file in script1.sh script2.sh script3.sh ... script10.sh; do
ed "$file" <<ED_COMMANDS
8d
8i
$line8
.
21d
21i
${line21[$file]}
.
w
q
ED_COMMANDS
done
Responderei a ambas as perguntas, mas, como regra geral, não combine perguntas como essa, divida-as em postagens separadas.
Perl:
for f in *.sh; do
perl -i -lne '$.==8 ? print "This is line 8" : print;' "$f";
done
awk e variantes:
for f in *.sh; do
awk '{if(NR==8){print "This is line 8"}else{print}}' "$f" > fifo &&
mv fifo "$f";
done
Primeiro, criei um arquivo com as substituições que quero fazer. Por exemplo:
script1.sh foo1
script2.sh foo2
script3.sh foo3
script4.sh foo4
Em seguida, leia esse arquivo para realizar as substituições:
while read f s; do
export s;
perl -i -lne '$.==8 ? print "$ENV{s}" : print;' "$f";
done < sublist.txt
Tags vi text-processing awk bash-script