Encontrei um excelente uso de sed
para substituir e usar seu estado bem-sucedido como condição para imprimir a linha:
$ seq 3 | sed -n 's/2/B/ p'
B
Eu estou querendo saber se este formulário curto pode ser estendido para fazer mais ações. Como,
- imprimir a linha somente se a substituição for bem-sucedida, mas
- antes de imprimir, preciso fazer mais substituições
Isso seria possível? Eu tentei o seguinte, mas falhei:
$ seq 3 | sed -n 's/2/B/ {p}'
sed: -e expression #1, char 8: unknown option to `s'
Você pode usar
/2/
como endereço para um comando mais complexo:Isso iria, para qualquer linha contendo pelo menos um
2
, substituir a primeira ocorrência de2
porB
(nesse caso, essa substituição também poderia ser abreviada paras//B/
onde a expressão regular vazia significa "usar a expressão correspondente mais recente") e, em seguida, descartar a linha se ele agora contém a substringBB
. Em seguida, a linha seria gerada (se não fosse descartada). Outras linhas não seriam produzidas, devido a-n
.Você também pode usar
Isso excluiria todas as linhas que não contêm
2
e aplicariaother commands
nas linhas restantes.Usar várias expressões, cada uma usando
-e
, é a maneira padrão de aplicar uma série de comandos a um fluxo de entrada comsed
. A maioria das implementações atuaissed
também entende a separação de expressões com;
. GNUsed
não precisa ver um;
antes de um arquivo}
.p
aqui está uma bandeira para osed
comando, não é op
sed
comando.Para fazer algo (além de
p
imprimir o espaço padrão resultante ouw
ritmá-lo em um arquivo,w
sendo outro dos sinalizadores que se pode usar com os
comando) somente se uma substituição foi feita, você pode usar ot
comando (ou oT
comando no GNUsed
) que ramifica para algum rótulo (ou para o final se não houver rótulo) se houver uma substituição (se não houver-T
), então você pode fazer:GNU específico:
Que é como:
Ou você pode usar:
Onde usar um regexp vazio reutiliza o anterior como em
ed
.Se você precisar fazer algo diferente,
s/old/new/
seria melhor usar awk do que sed para alguma combinação de clareza, robustez, portabilidade, facilidade de manutenção, etc.:Você pode agrupar comandos com "{ .... }". A forma geral é:
"cmd" aqui é qualquer comando sed regular, como "s/.../.../", mas também "p", "q", etc. Pense nisso como uma "regra", aplicável a todos linhas correspondentes ao regexp. Você também pode negar a regra usando um ponto de exclamação entre o regexp e a chave de abertura. Nesse caso, a regra é aplicada a todas as linhas que não correspondem ao regexp.
Aqui está um exemplo que imprime todas as linhas somente de comentários desde o início de um script até a primeira linha sem comentários:
Todas as linhas que começam com um "#" correspondem à regra e, portanto, são apenas impressas (não usamos a opção "-n" para suprimir isso). A primeira linha (na verdade todas as linhas, mas efetivamente apenas a primeira é processada) que não corresponde ao regexp aciona a regra que simplesmente sai do sed.
Mas há também outro dispositivo que é ainda mais poderoso do que usar regras: você define os chamados "rótulos". Lugares simbólicos para os quais você ramifica com um comando do tipo GOTO. É assim que funciona:
1) os scripts sed de ramificação incondicional funcionam assim: a primeira linha de entrada é lida, então todos os comandos sed são aplicados a ela, um após o outro (se a linha for alterada, outros comandos são aplicados a esta linha alterada) até a última comando é alcançado. Se a opção "-n" não for usada, o resultado será impresso em . Só então a próxima linha de entrada é lida e o processo começa de novo, até que a última linha de entrada seja processada.
Existe uma maneira de alterar a ordem em que os comandos são aplicados à linha atual:
Este comando não faz nada por si só, mas pode ser usado por outros comandos para ramificar para este local. Você talvez se lembre de linguagens como BASIC e seu comando "goto"? Isso marca um rótulo para o qual um comando "ir para" (como) subsequente pode pular. O comando sed incondicional para ramificar para um rótulo definido anteriormente é
O "b" significa "ramo". corresponde ao que você definiu com o comando ":". Se você omitir o rótulo, a execução desvia para o final do script.
Aqui está um exemplo: você obtém um programa, mas infelizmente o recuo do código é feito com caracteres de tabulação em vez de espaços e você deseja alterar isso. Obviamente, você deseja alterar apenas as guias na frente de qualquer código, não as guias dentro do código, pois podem ser necessárias. Infelizmente, não há nenhum dispositivo em expressões regulares para isso diretamente, então você mesmo deve implementá-lo. O algoritmo é: contanto que uma linha esteja no formato espaço em branco, seguida por uma tabulação, altere esta primeira tabulação para 8 espaços em branco e repita na mesma linha até que nenhuma tabulação esteja na frente de qualquer texto. Só então imprima a linha. Essa estrutura semelhante a um loop é configurada usando um comando ":" e um "b". Observe que eu uso \b (em branco) e \t (tab) aqui para tornar os diferentes tipos de espaço em branco legíveis.
2) ramificação condicional Agora que você sabe como configurar rótulos e ramificar para eles, há uma reviravolta ainda maior: você pode ramificar para tal rótulo dependendo de um comando s/.../.../ executado antes de ser bem-sucedido (ou seja: mudou alguma coisa) ou não. Os comandos para fazer isso são:
que desvia para se um dos s/../../-comandos fez uma substituição bem-sucedida desde que a última linha foi lida OU desde a última execução do comando at ou T e
que é a contraparte negada de "t". Ele ramifica se nenhum comando s foi bem-sucedido.
Aqui está um exemplo simples de como isso funciona. Não faz nada particularmente útil, mas mostra o princípio: o sed-script leva apenas a primeira linha de qualquer entrada. Se o primeiro caractere for "a", "b" ou "c", imprime "SIM", caso contrário, "NÃO".
O fluxo de controle é simples: primeiro tenta-se uma substituição onde o primeiro caractere é trocado por um "x" se for "a", "b" ou "c". Caso seja bem-sucedido, o comando de ramificação "t yes" irá ramificar para o lael "yes", onde toda a linha é alterada para "YES" e sed sai (o comando "q"). Se esta substituição não for bem-sucedida, o comando "t" é passado e o comando "b" é executado, saltando para o rótulo "não".
Experimente várias entradas (
echo "..." | sed <script>
é bom o suficiente) para ver como funciona, depois mude o comando "t" para um "T" e observe o efeito nos resultados.