aqui está meu roteiro:
#! /bin/bash
# C-band Edit
dqt='"'
str5="polarization=${dqt}2${dqt}"
for x in {3600..4200} do;
sed -i "/$str5.*$x/s/$x/$((x-600))/" satellites.xml
done
tudo o que quero fazer é substituir o número x por x-600 entre 3600 e 4200 em todas as linhas que têm str5 em satellites.xml, mas o script acima me dá erro de sintaxe
Apenas me ocorreu que você não quis dizer a string literal
x-600
, você quis dizer "subtrair 600 de cada valor encontrado entre 3600 e 4200". Nesse caso, use perl, não sed:Isso usa o
/e
modificador regex do perl para fazer com que o lado direito ($&-600
) seja avaliado como uma expressão perl .$&
é uma variável perl que contém o valor da correspondência, então$&-600
significa subtrair 600 desse valor.Vou deixar minha resposta original abaixo caso fosse isso que você realmente queria. Também porque tem explicações úteis que ainda são um pouco relevantes para a resposta perl acima.
Assim como o sed, o perl tem uma
-i
opção para edição no local para que você possa aplicá-la diretamente ao seu arquivo satellites.xml. Vejaman perlrun
para detalhes.Também digno de nota: Você provavelmente deve usar um analisador XML quando estiver trabalhando com arquivos XML. Felizmente, o perl tem vários para escolher, por exemplo, XML::Parser ou a coleção libxml-perl .
Não tenho uma amostra de sua entrada real, então criei uma que demonstrará o que será alterado e o que não será:
Traduzido aproximadamente para o inglês, isso é "se a linha atual contiver $str5 (
polarization="2"
), aplique essas trêss///
operações a ela".Notas:
Não há necessidade de fazer um loop de 3600..4200. Isso fará todas as alterações em uma execução de
sed
, não em 600 execuções.Você queria que os valores de 3600-4200 fossem alterados. Isso significa que você precisa de 3 operações de pesquisa e substituição:
Alternativamente, isso pode ser feito com duas
s///
operações, combinando as duas últimas em uma:Provavelmente existem muitas outras maneiras de otimizar os regexes, mas quanto mais você fizer isso, mais difícil será ler e modificar no futuro.
3964
,4155
, e4200
foram alterados.3500
e4255
não foram, eles ficam fora do intervalo desejado.[0-9]
não funcionará como esperado em algumas localidades (onde houver outros caracteres nesse intervalo). Não sei exatamente quais localidades, mas já vi isso mencionado com frequência suficiente para saber que[0-9]
não pode ser totalmente confiável. Se isso afetar você, você pode usar[[:digit:]]
em vez de[0-9]
, ou usarperl -p
em vez desed
(assim você pode usar\d
em vez de[0-9]
). O mesmo se aplica ao intervalo[6-9]
, use[6789]
em vez disso.Por fim, tenha muito cuidado com o que você coloca na
$str5
variável. Por estar sendo interpolado em umsed
comando, será muito fácil quebrar o script sed (por exemplo, se$str5
contiver um/
, ele quebrará a/$str5/
correspondência). O sed não sabe que seu script veio parcialmente de uma variável do shell, tudo o que ele vê é o script que foi dado para executar.Além disso, a string inteira será interpretada por sed como uma expressão regular - isso significa que os metacaracteres regex não serão interpretados como caracteres literais, a menos que sejam escapados com um
\
. por exemplo.
, será interpretado como "qualquer caractere" em vez de um ponto literal, a menos que seja escapado como\.
Sua tentativa está correta em princípio, você acabou de fechar a lista antes do
do
com ponto e vírgula, como frabjous apontou:Mas observe que isso fará com que você edite o arquivo 601 vezes "no local", criando e excluindo centenas de novos arquivos cada vez que você executar isso.
Para evitar isso você pode
sed
um pouco de compreensão básica de números para fazer isso de uma só vez, o que é divertido, mas não é realmente útilpython
,perl
ouawk
sed
:A substituição produzirá o
sed
script