Com o bash, estou executando isto: declare -p | grep 'declare -- '
Isso imprime linhas inteiras. Quero imprimir essas mesmas linhas, mas queria excluir a correspondência em si. ou seja, posso fazer ... | grep pattern | sed 's/pattern//'
como um único comando? Seria como o oposto da -o
opção.
Meu comando gera isso:
...
declare -- MAX_CONNECTIONS_PER_SERVER="6"
declare -- OPTERR="1"
declare -- OSTYPE="linux-gnu"
...
Mas eu quero produzir isso:
...
MAX_CONNECTIONS_PER_SERVER="6"
OPTERR="1"
OSTYPE="linux-gnu"
...
Normalmente, eu apenas canalizaria isso para sed
, mas coincidentemente, eu queria fazer isso duas vezes hoje. Eu olhei para a página de manual, mas não vi nenhuma opção que pudesse fazer isso.
Retornar apenas a parte de uma linha após um padrão de correspondência é uma pergunta muito semelhante. Talvez seja até uma duplicata. Pode-se argumentar que o meu é um pouco mais estreito: é garantido que o padrão que estou grepping e o padrão que estou removendo serão os mesmos. Eu quero remover x
. A questão quer remover .*x
.
Isso deveria ser apenas:
Mas esse tipo de abordagem ao analisar a saída de
declare -p
é falho.E se houver um
VAR=$'\ndeclare -- reboot #'
no ambiente, por exemplo, e você alimentar essa saída em um shell para interpretação?Observe também que, para variáveis declaradas, mas sem valor atribuído,
bash
imprime:declare -- VARNAME
, portanto, depoisdeclare reboot
de , o código acima também será geradoreboot
.Você poderia alterá-lo para:
Para restringir a variáveis atribuídas, mas isso ainda não resolveria problemas com variáveis que contêm novas linhas (o que é comum mesmo que apenas para a
$TERMCAP
variável).Em vez disso, você pode usar esse tipo de hack:
Onde avaliamos a saída de
declare -p
where escapamos(
,)
,[
e]
usamos em representações de array e array associativo, depois de ter redefinidodeclare
como uma função que imprime seu segundo argumento se o primeiro for--
. Use por sua conta e risco, a saída do bash édeclare -p
conhecida por ser insegura para avaliação no passado, também é possível que adicionar esse escape comsed
adiciona complicações, especialmente comsed
implementações que têm um limite no comprimento das linhas que aceitam.em
zsh
, você poderia fazer:Imprimir as definições de variáveis que são escalares e não possuem nenhum atributo (nem mesmo especial nem vinculado ) como parece ser sua intenção.
Observe, no entanto, que não funciona se for chamado dentro de uma função (nesse caso, ele declararia todas essas variáveis como locais) ou se a
typesetsilent
opção estiver ativada.Outra abordagem que contornaria isso e lhe daria mais controle sobre como o valor é cotado seria:
q+
fornece um estilo de citação semelhante ao usado portypeset
. Useqq
para um estilo de citação mais seguro se você pretende usar essa saída em um shell (que pode não ser zsh, ou não da mesma versão, ou não na mesma localidade ou OS/libc).Se disponível, use
grep -P
:Observe que sua abordagem geralmente não funcionará bem, porque as variáveis podem conter novas linhas com as quais você cortará
grep
e obterá erros de sintaxe.Veja por exemplo:
A.
sed
egrep
O shell exibe os valores de algumas variáveis em várias linhas porque elas contêm novas linhas incorporadas.
grep
esed
são projetados para pesquisar padrões na mesma linha, linha por linha (o caractere de nova linha é usado como um delimitador embutido em código).Transporte em ônibus
awk
O awk pode selecionar um padrão em uma linha, mas também aplicar regras condicionalmente.
1. Selecione as linhas correspondentes
declare --
declare
As duas regras anteriores permitem 1. exibir as variáveis que não possuem atributos e 2. os valores exibidos nas linhas subsequentes para valores de várias linhas.
Podemos usar uma entrada de amostra para mostrar uma visão geral da correspondência de padrões.
O valor da variável
HOSTNAME
é exibido com sucesso porque as duas regras correspondem consecutivamente: uma regra corresponde em uma linha e a outra na próxima linha. No entanto, também vemos que oGREETINGS
valor da variável é exibido parcialmente. De fato, embora a linha não comece com o padrãodeclare --
, a linha subsequente (uma substring do valor da variável, cfWorld!"
) é exibida porque a linha (ou "registro") corresponde à segunda regra!/^declare/
.Como os valores de várias linhas são subsequentes, é necessário exibir apenas algumas linhas consecutivas.
2. Verifique o valor da variável shell
É oportuno apresentar agora o algoritmo utilizado para entender melhor a complexidade do código.
Antes de tudo, você deve saber que o Awk verifica todas as regras cada vez que lê um registro (por padrão, a linha atual). No entanto, você deve considerar o processamento feito anteriormente (no registro anterior). Em outras palavras, o programa precisará conhecer seu estado enquanto processa a próxima linha: qual é a variável do shell analisada? Para isso, definimos uma variável "booleana" chamada
scan
.O código é, sem dúvida, complexo. É uma sequência ordenada de instruções condicionais mutuamente exclusivas (como o XOR lógico). Para obter mais informações, leia a seção "Por que o código é tão complicado?".
A. A variável não tem valor
O terceiro campo não é uma atribuição de variável shell se não contiver um sinal de igual, é apenas um nome de variável.
B. A variável tem um valor
O valor de uma variável pode conter caracteres especiais que são escapados usando aspas duplas.
Existem dois tipos de atribuição de variáveis: a declaração de uma variável escalar e a declaração de uma variável de matriz.
De qualquer forma, o valor é delimitado por um par de caracteres específicos, ou
"
e"
ou(
e)
. Se os delimitadores correspondentes estiverem na mesma linha, o valor da variável não conterá caracteres de nova linha. Caso contrário, a próxima linha deve ser exibida até o delimitador correspondente.O delimitador de abertura está em uma posição específica armazenada na
beg
variável enquanto o delimitador de fechamento deve ser pesquisado (usando aend
variável).Nota:
match()
é uma função Awk interna que retorna as posições inicial e final da substring que correspondeu ao padrão (usando as variáveis predefinidasRSTART
eRLENGTH
). Aqui salvamos o caractere logo após o sinal de igualbeg
e o último caractere do registro emend
.uma. O valor não contém novas linhas incorporadas
Os caracteres
beg
eend
são delimitadores emparelhados.Se o segundo e o terceiro testes forem falsos, isso indica que não é necessário varrer a próxima linha. De fato, a atribuição da variável Awk
scan = 0
é equivalente ao valor de verdade "falso".Em termos concretos, isso significa que as linhas contendo substrings que não estão associadas aos padrões selecionados (variáveis desejadas) não são exibidas. Se tomarmos o exemplo da seção "1. Selecione as linhas correspondentes", isso permite não exibir a substring
World!"
que é o valor deGREETINGS
(declare -x
).b. O valor contém novas linhas incorporadas
Esta instrução condicional indica que o valor ainda não está delimitado corretamente. Portanto, o delimitador está necessariamente localizado em outra linha (uma linha subsequente que é consecutiva à linha atual). Neste caso,
scan = 1
indica para escanear a próxima linha,scan
torna-se "true" em um teste lógico.Estritamente falando, a atribuição da variável
scan
a0
não é funcionalmente útil, mas é um lembrete para o leitor de que , por padrão, essa variável é definida como0
. Na verdade, temos a mesma "sequência" naif
parte correspondente, mas nesta parte a atribuição de variáveisscan = 0
é realmente útil (consulte a seção "O valor não contém novas linhas incorporadas").C. Exibir a próxima (próxima...) linha
;; A definir
Por que esse código é tão complicado?
Este código é complicado porque verifica as várias combinações dos delimitadores. Isso não é complicado, mas os testes são específicos.
O programa Awk
Você pode fazer isso facilmente com Perl:
Se você usar ack , você pode fazer isso:
resultado