Formatando texto - insira nova linha antes das linhas comentadas

0

Eu tenho algum texto que eu gostaria de arrumar. Basicamente, para adicionar uma nova linha antes de cada comentário, há uma linha vazia entre cada duas linhas. Aqui está uma amostra do conteúdo a ser modificado para referência:

# quickly backup or copy a file with bash
cp filename{,.bak}
# Rapidly invoke an editor to write a long, complex, or tricky command
ctrl-x e
# Copy ssh keys to user@host to enable password-less ssh logins.
$ssh-copy-id user@host
# Empty a file
> file.txt
# Execute a command without saving it in the history
<space>command
# Capture video of a linux desktop
ffmpeg -f x11grab -s wxga -r 25 -i :0.0 -sameq /tmp/out.mpg
# Salvage a borked terminal
reset
# start a tunnel from some machine's port 80 to your local post 2001
ssh -N -L2001:localhost:80 somemachine
# Execute a command at a given time
echo "ls -l" | at midnight
# Query Wikipedia via console over DNS
dig +short txt <keyword>.wp.dg.cx
# currently mounted filesystems in nice layout
mount | column -t
# Update twitter via curl
curl -u user:pass -d status="Tweeting from the shell" http://twitter.com/statuse
s/update.xml
# Place the argument of the most recent command on the shell
'ALT+.' or '<ESC> .'
# output your microphone to a remote computer's speaker
dd if=/dev/dsp | ssh -c arcfour -C username@host dd of=/dev/dsp    

Eu gostaria que fosse assim:

# quickly backup or copy a file with bash
cp filename{,.bak}

# Rapidly invoke an editor to write a long, complex, or tricky command
ctrl-x e

# Copy ssh keys to user@host to enable password-less ssh logins.
$ssh-copy-id user@host

# Empty a file
> file.txt

# Execute a command without saving it in the history
<space>command

# Capture video of a linux desktop
ffmpeg -f x11grab -s wxga -r 25 -i :0.0 -sameq /tmp/out.mpg

# Salvage a borked terminal
reset

Eu tentei usar o OSX sed para obter a formatação correta, mas sem sucesso:

sed 's/^\#/\n&/g' <filename.txt>

Não me oponho a usar awk se essa for a melhor maneira de resolver o problema.

    
por lmind 17.10.2017 / 15:28

3 respostas

2
awk '{if (/^#/) {if (!n++ && NR>1) print ""} else n=0; print}'

inseria uma linha vazia antes da primeira linha em uma sequência de linhas que começam com # . Então, em uma entrada como:

xx
#1
#2
yy

dá:

xx

#1
#2
yy

n conta o número de linhas de comentários em grupos de linhas de comentário. Imprimimos uma linha vazia ( print "" ) se estivermos na primeira linha de cada grupo de linhas de comentário (e excluiremos a primeira linha de entrada com NR>1 ).

    
por 17.10.2017 / 15:39
2

O sed correto é

sed '2,$s/^#/\n#/' filename

Isso adicionará uma nova linha somente antes das linhas que começarem com um comentário.

O 2,$ informa sed para começar a avaliar da segunda linha até a última linha do arquivo. No comando substituto s , estamos procurando linhas que começam com o símbolo de comentário ( ^# ) e substituímos essa ocorrência na linha por uma nova linha e o símbolo de comentário encontrado ( \n# ).

Você não precisa da opção g no final do comando porque não deseja substituir todos os # encontrados em uma linha.

Isso só funcionará com o GNU sed , porque \n na string de substituição é indefinida no padrão. Mas você pode fazer

sed '1n;/^#/{x;p;x;}' filename

em vez disso. O 1n imprime a primeira linha e continua com o próximo. Desta forma evitamos o "endereçamento" das linhas 2 até o final. Portanto, agora podemos endereçar todas as linhas que começam com # e para todas aquelas dentro do {} são executadas: x troca o conteúdo do espaço padrão e armazena espaço. O espaço de espera está vazio, então p imprime uma linha vazia, o segundo x altera os buffers de volta, então o espaço de espera está vazio novamente e a linha original é impressa por padrão.

    
por 17.10.2017 / 15:49
0

Também é possível adicionar uma nova linha antes da primeira linha de cada bloco de comentários usando sed branches:

sed -n '1{p;d}; /^#/{s/^/\n/;:x;p;n;/^#/bx}; /^#/!p' filename

Aqui:

  • 1{p;d} evita adicionar uma nova linha antes da primeira linha.

  • /^#/{s/^/\n/;:x;p;n;/^#/bx} é adicionar uma nova linha antes de cada bloco de comentários. Aqui está um resumo do que ele faz:

    • /^#/ corresponde a linhas que começam com # . Para essas linhas, sed executará o bloco de comandos dentro de chaves.

    • s/^/\n/ adiciona uma nova linha antes da linha correspondente.

    • :x;p;n;/^#/bx define um rótulo x , imprime o espaço padrão ( p ), substitui o espaço padrão pela próxima linha de entrada ( n ) e retorna para x se o/^#/bx new pattern space é um comentário ( /^#/!p ).

  • %code% imprime normalmente linhas que não são comentários.

EDIT: Você também pode tornar o comando indempotente da seguinte forma:

sed -n '1{p;d}; /^\s*$/bx; /^#/{s/^/\n/;:x;p;n;/^#/bx}; /^#/!p' filename
    
por 17.10.2017 / 16:54