Que tal
perl -pe '$n=1 if s/^dotan/#$&/; s/^[^#]/#$&/ unless $n==1;' file
ou a mesma ideia no awk:
awk '(/^dotan/){a=1; sub(/^/,"#",$1)} (a!=1 && $1!~/^#/){sub(/^/,"#",$1);}1; ' file
Considere um arquivo de texto users.txt
:
#alice
#bob
charlie
dotan
eric
Eu preciso comentar tudo, desde (exclusivo) a última linha comentada até (inclusive) dotan
. Este é o resultado:
#alice
#bob
#charlie
#dotan
eric
Existe um bom sed
oneliner para fazer isso? Eu ficarei feliz com qualquer ferramenta, não apenas sed
, realmente.
Atualmente, estou recebendo o número da última linha comentada assim:
$ cat -n users.txt | grep '#' | tail -n1
2 #bob
Depois, adiciono um e comento com sed
:
$ sed -i'' '3,/dotan/ s/^/#/' users.txt
Eu sei que eu poderia ser inteligente e juntar tudo isso com um pouco de bc
em um one-liner feio. Certamente deve haver um caminho mais limpo?
Se as linhas comentadas existentes formarem um único bloco contíguo, você poderá compará-las a partir da primeira linha comentada, comentando apenas as linhas até e incluindo o padrão final que ainda não foram comentadas
sed '/^#/,/dotan/ s/^[^#]/#&/' file
Se os comentários existentes não forem contíguos, então, devido à natureza gananciosa da correspondência do intervalo sed, acho que você precisaria fazer algo como
tac file | sed '/dotan/,/^#/ s/^[^#]/#&/' | tac
i.e. combinar para cima do padrão final para o 'primeiro' comentário - obviamente isso não é tão conveniente se você quiser uma solução no local.
Você pode manipular ambos os casos (linhas comentadas em um único bloco contíguo ou intercaladas entre linhas não comentadas) com uma única invocação sed
:
sed '1,/PATTERN/{/^#/{x;1d;b};//!{H;/PATTERN/!{1h;d};//{x;s/\n/&#/g}}}' infile
Isso processa somente as linhas no intervalo 1,/PATTERN/
. Ele e x
alterações retêm espaço w. espaço padrão toda vez que uma linha é comentada (portanto, nunca há mais de uma linha comentada no buffer de retenção) e anexa todas as linhas que não são comentadas no espaço H
old (quando na primeira linha, 1d
e% respectivamente1h
também são necessários para remover a linha vazia inicial no buffer de retenção).
Quando ele atinge a linha PADRÃO correspondente, ele também o anexa ao buffer H
old, e x
altera os buffers e, em seguida, substitui cada caractere de \n
ewline no espaço de padrão por \n
ewline e #
(ou seja, todas as linhas no espaço padrão agora começarão com #
, incluindo a primeira linha, pois a primeira linha no espaço de retenção é sempre uma linha comentada).
Com uma amostra infile
:
alice
#bob
bill
#charlie
ding
dong
dotan
jimmy
#garry
em execução:
sed '1,/dotan/{ # if line is in this range -start c1
/^#/{ # if line is commented -start c2
x # exchage hold space w. pattern space
1d # if 1st line, delete pattern space
b # branch to end of script
} # -end c2
//!{ # if line is not commented -start c3
H # append to hold space
/dotan/!{ # if line doesn't match dotan -start c4
1h # if 1st line, overwrite hold space
d # delete pattern space
} # -end c4
//{ # if line matches dotan -start c5
x # exchage hold space w. pattern space
s/\n/&#/g # add # after each newline character
} # -end c5
} # -end c3
}' infile # -end c1
saídas:
alice
#bob
bill
#charlie
#ding
#dong
#dotan
jimmy
#garry
então está comentando apenas linhas de (e excluindo) #charlie
até (e incluindo) dotan
e deixando as outras linhas intactas.
Claro, isso pressupõe que sempre haja pelo menos uma linha comentada antes da linha correspondente a PATTERN
. Se esse não for o caso, você pode adicionar uma verificação adicional antes da substituição: /^#/{s/\n/&#/g}
Aqui está outro sed
:
sed -e:n -e'/\n#.*\ndotan/!{$!{N;/^#/bn' \
-eb -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/#/g' \
-et -e\} -eP\;D <in >out
Isso faz o que você pede. Ele apenas funciona em uma pilha - construindo-a quando necessário e pelo tempo que for necessário entre ocorrências de linhas comentadas, e descarregando o buffer antigo em favor da nova linha comentada mais adiante na entrada quando encontrar uma. Imagem ...
Desculpe,nãoseiporquefizisso.Masveioàmente.
Dequalquerforma,sed
espalhaseusbuffersentrecadaúltimalinhacomentadaemqualquersérie,nuncaretendomaisnadaemseubufferdoqueonecessáriopararastrearcomprecisãoaúltimaocorrênciacomentadaeseaqualquermomentoencontraraúltimalinhaenquantoaofazerisso,eletentaráainstruçãodeexecuçãofinalg
lobalearamificaçãot
esttodoobufferaserimpresso,senãoP
rinttodasaslinhasqueeleliberardeseubufferassimqueocorrer./p>
Euachoqueissoéoquetrouxeosacordeõesparaamente...
printf %s\n \#alice \#bob charlie dotan eric \
\#alice \#bob charlie dotan eric \
\#alice \#bob charlie dotan eric |
sed -e:n -e'l;/\n#.*\ndotan/!{$!{N;/^#/bn' \
-eb -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/#/g' \
-et -e\} -eP\;D
#alice
#alice\n#bob$
#alice\n#bob\ncharlie$
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob
#charlie
#dotan
eric
Existe apenas uma diferença entre este comando e o que está acima e esse é o comando l
ook no topo. Quando nós l
ook no espaço de padrão de sed
como funciona, podemos ter uma idéia melhor do que acontece nos bastidores e uma melhor compreensão de como direcionar seus esforços.
Nesse caso, podemos assistir sed
stack input até encontrar uma segunda ocorrência de \n#.*\ndotan
na entrada e quando começar a imprimir a saída anterior de uma linha por vez. É legal. Eu aprendi muito trabalhando nisso.
Tags text-processing sed