Estou confuso com os dois conceitos em sed: espaço de retenção e espaço de padrão. Alguém pode ajudar a explicá-los?
Aqui está um snippet do manual:
h H Copy/append pattern space to hold space. g G Copy/append hold space to pattern space. n N Read/append the next line of input into the pattern space.
Esses seis comandos realmente me confundem.
echo $'1\n2\n3\n4' | sed -n '1~2h;2~2{p;x;p}'
info sed
. É muito mais detalhado do que a página de manual simples.Respostas:
Quando sed lê um arquivo linha por linha, a linha que foi lido no momento é inserido no padrão de buffer (espaço padrão). O buffer de padrão é como o buffer temporário, o bloco de notas onde as informações atuais são armazenadas. Quando você diz ao sed para imprimir, ele imprime o buffer padrão.
O buffer de retenção / espaço de retenção é como um armazenamento de longo prazo, de forma que você pode capturar algo, armazená-lo e reutilizá-lo mais tarde quando o sed estiver processando outra linha. Você não processa diretamente o espaço de retenção; em vez disso, você precisa copiá-lo ou anexar ao espaço do padrão se quiser fazer algo com ele. Por exemplo, o comando de impressão
p
imprime apenas o espaço do padrão. Da mesma forma,s
opera no espaço padrão.Aqui está um exemplo:
(a opção -n suprime a impressão automática de linhas)
Há três comandos aqui:
1!G
,h
e$p
.1!G
tem um endereço,1
(primeira linha), mas!
significa que o comando será executado em todos os lugares, exceto na primeira linha.$p
por outro lado, só será executado na última linha. Então o que acontece é o seguinte:h
copia a primeira linha para o espaço de espera .G
, anexando o conteúdo do buffer de retenção ao buffer de padrão, separando-o por uma nova linha. O espaço padrão agora contém a segunda linha, uma nova linha e a primeira linha.h
comando insere o conteúdo concatenado do buffer de padrão no espaço de retenção, que agora contém as linhas reversas dois e uma.Finalmente, depois que a última linha foi lida e o espaço de retenção (contendo todas as linhas anteriores em ordem reversa) foi anexado ao espaço do padrão, o espaço do padrão é impresso
p
. Como você já deve ter adivinhado, o procedimento acima faz exatamente o que otac
comando faz - imprime o arquivo ao contrário.fonte
'195,210{/add/p}'
… É possível extrair a última linha de um grupo de linhas envolvidas em um padrão?@Ed Morton: Eu discordo de você aqui. Achei
sed
muito útil e simples (depois de entender o conceito do padrão e manter os buffers) criar uma maneira elegante de fazer o grep de várias linhas.Por exemplo, vamos pegar um arquivo de texto que contém nomes de host e algumas informações sobre cada host, com muito lixo entre as quais eu não me importo.
Para mim, um script awk para obter apenas as linhas com o nome do host e a
info
linha correspondente levaria um pouco mais do que sou capaz de fazer com o sed:a saída se parece com:
(Observe que
Host: foo1
aparece duas vezes na saída.)Explicação:
-n
desativa a saída, a menos que seja explicitamente impressoHost:
linha no buffer de retenção (h)Host:
linha, depois troca novamente (x) e imprime (p) a linha Info :.Sim, este é um exemplo simplista, mas eu suspeito que este seja um problema comum que foi rapidamente resolvido por uma linha simples do sed. Para tarefas muito mais complexas, como aquelas nas quais você não pode confiar em uma determinada sequência previsível, o awk pode ser mais adequado.
fonte
grep 'Host\|Info'
awk
equivalente ao seu código sed é bem curto também:awk '/Host:/{hold=$0}; /Info/{print hold; print;}' myfile.txt
Embora a resposta de @janeiro e o exemplo sejam bons, a explicação não foi suficiente para mim. Tive que pesquisar e aprender muito até conseguir entender exatamente como
sed -n '1!G;h;$p'
funciona. Portanto, gostaria de elaborar o comando para alguém como eu.Em primeiro lugar, vamos ver o que o comando faz.
Inverte a entrada como
tac
comando faz.sed
lê linha por linha, então vamos ver o que acontece no espaço do patten e no espaço de espera em cada linha. Como oh
comando copia o conteúdo do espaço do padrão para o espaço de retenção, ambos os espaços têm o mesmo texto.Na última linha,
$p
imprimed\nc\nb\na$
que é formatado paraSe quiser ver o espaço do padrão para cada linha, você pode adicionar um
l
comando.Achei muito útil assistir a este tutorial em vídeo Entendendo como funciona o sed , pois o cara mostra como cada espaço será utilizado passo a passo. O hold spaced é referido no 4º tutorial, mas recomendo assistir a todos os vídeos se você não estiver familiarizado
sed
.Também o documento GNU sed e o tutorial Sed de Bruce Barnett são referências muito boas.
fonte