Como inserir uma nova linha antes de um padrão em uma linha?
Por exemplo, isso inserirá uma nova linha atrás do padrão regex.
sed 's/regex/&\n/g'
Como posso fazer o mesmo, mas na frente do padrão?
Dado esse arquivo de entrada de amostra, o padrão para combinar é o número de telefone.
some text (012)345-6789
Apenas repetindo a resposta Como faço para inserir uma nova linha / linebreak após uma linha usando sed aqui:sed '/regex/G'
@NilsvonBarth, por que uma pergunta direta é uma pergunta ruim?
Isso funciona bashe é zshtestado no Linux e OS X:
Em geral, para $seguido por uma string literal entre aspas simples bashrealiza a substituição da barra invertida no estilo C, por exemplo, $'\t'é traduzida para uma guia literal. Além disso, o sed deseja que seu literal de nova linha seja escapado com uma barra invertida, daí o \anterior $. E, finalmente, o próprio sinal de cifrão não deve ser citado para que seja interpretado pelo shell; portanto, fechamos a cotação antes da $e depois a abrimos novamente.
Edit : Como sugerido nos comentários por @ mklement0, isso também funciona:
sed $'s/regexp/\\\n/g'
O que acontece aqui é: todo o comando sed agora é uma string no estilo C, o que significa que a barra invertida que o sed precisa ser colocada antes que a nova linha literal agora seja escapada com outra barra invertida. Embora seja mais legível, nesse caso, você não poderá fazer substituições de string de shell (sem torná-lo feio novamente).
Isso me dá "nova linha sem escape dentro do padrão substituto" no OSX.
@ Matt Gibson, isso é muito estranho, porque "nova linha sem escape" é fornecida apenas quando você tem uma nova linha real sem uma barra invertida dentro do padrão de substituição. Meu código acima também funciona em alguns outros shells, por exemplo, zsh, ksh.
@ Matt Gibson ... ou se você esquecer a barra invertida antes de '$' \ n no meu código.
Conforme escritas, essas expressões substituem completamente a regex por uma nova linha, em vez de inserir uma nova linha no meio de uma linha existente, conforme solicitado. Veja como eu usei uma forma modificada de esta resposta para inserir uma nova linha entre dois padrões encontrados: sed '\(first match\)\(second match\)/\1\'$'\n''\2/g'. Observe as duas aspas simples após o \ n. O primeiro fecha a $seção " " para que o restante da linha não seja afetado por ele. Sem essas aspas, o \ 2 foi ignorado.
— David Ravetti
Outra opção é usar uma única seqüência ANSI C-citada : sed $'s/regexp/\\\n/g', o que melhora a legibilidade - a única ressalva é que você precisa então de dobrar todos os literais \ caracteres.
Algumas das outras respostas não funcionaram na minha versão do sed. Mudar a posição &e \nfuncionou.
sed 's/regexp/\n&/g'
Editar: parece não funcionar no OS X, a menos que você instale gnu-sed.
Não tenho certeza se isso funciona em todas as versões do sed. Eu tentei isso no meu Mac eo \ n só fica de saída como 'n'
Passei 15 minutos no mac no meu trabalho, antes de ler sua resposta. Vai a Apple!
— 9777 Rick7
Para aqueles que usam homebrew: brew install gnu-sedseguido porgsed 's/regexp/\n&/g'
— aaaaaa 5/05
... seguido porecho 'alias sed=gsed' >> ~/.bashrc
No sed, você não pode adicionar novas linhas no fluxo de saída com facilidade. Você precisa usar uma linha de continuação, o que é estranho, mas funciona:
Veja aqui para detalhes. Se você quiser algo um pouco menos estranho, tente usar perl -pecom grupos de correspondência em vez de sed:
$1 refere-se ao primeiro grupo correspondente na expressão regular, onde os grupos estão entre parênteses.
Por que você diz que não pode adicionar novas linhas? Você pode simplesmente fazer o sed 's / regexp / & \ n / g' É isso aí
Este é o menos coisa olhando hacky que você pode fazer em um Mac para inserir nova linha (\ n não funciona em um Mac)
A versão perl pode ser modificado para fazer em edição lugarperl -pi -e 's/(.*)/\n$1/' foo
@Andres: (principalmente) implementações Sed somente de recursos POSIX, como a versão BSD que também vem com o OS X, não suportam sequências de escape de caracteres de controle na parte de substituição de uma schamada de função (ao contrário da implementação GNU Sed, que faz) . A resposta acima funciona com ambas as implementações; para uma visão geral de todas as diferenças, veja aqui .
No meu mac, o seguinte insere um único 'n' em vez de nova linha:
Isso substitui a nova linha:
— Roar Skullestad
Eu estava editando em linha sed -i '' -e ...e estava tendo problemas com um ^Mcursor M (ctrl + m) sendo gravado no arquivo. Acabei usando perl com os mesmos parâmetros.
Por favor, esteja ciente do fato de que o segundo código insere um código especial de nova linha LF CR (reverso do MS-DOS CR LF)! Os sistemas operacionais Unix e Mac OS X usam apenas LF ( \n).
Algo mais na minha expressão sed estava causando tanta infelicidade (apesar de funcionar bem sem a echo...e nova linha) que eu fiz isso no vim.
Ou simplesmente: sed "s/regexp/`echo`/g"- o que irá produzir um único LF vez de LF-CR
— mojubá
@mojuba: No: `echo`resultará na string vazia , porque as substituições de comandos invariavelmente cortam todas as novas linhas à direita. Não há como usar uma substituição de comando para inserir diretamente uma única nova linha (e inserir \n\r- isto é, um CR adicional - é uma péssima idéia).
+1 funcionou perfeitamente e muito stright-forward / fácil de lembrar
Esta resposta é realmente uma solução sed , em vez de uma solução bash . Qualquer coisa que use construções como $'\n'está contando com o shell para gerar a nova linha. Tais soluções podem não ser portáteis. Esta está. Claro, também é uma duplicata do segundo exemplo na resposta do tgamblin de 2009.
Nesse caso, eu não uso sed. Eu uso tr.
Isso pega a vírgula e a substitui pelo retorno de carro.
— user1612632
Achei que isso também funciona: cat Somefile | tr ',' '\n'YMMV
Você pode usar one-liners perl da mesma forma que o sed, com a vantagem da expressão regular completa do perl suporte (que é muito mais poderoso do que o obtido com o sed). Também há muito pouca variação entre as plataformas * nix - o perl geralmente é o perl. Portanto, você pode parar de se preocupar em como fazer com que a versão do sed do seu sistema específico faça o que você deseja.
Nesse caso, você pode fazer
-pe coloca o perl em um loop "execute and print", bem como o modo normal de operação do sed.
' cita todo o resto para que o shell não interfira
()ao redor do regex é um operador de agrupamento. $1no lado direito da substituição, imprime o que foi encontrado dentro desses parênteses.
Finalmente, \né uma nova linha.
Independentemente de você estar usando parênteses como um operador de agrupamento, você precisa escapar dos parênteses que está tentando corresponder. Portanto, uma regex para corresponder ao padrão listado acima seria algo como
\(ou \)corresponde a um paren literal e \dcorresponde a um dígito.
Eu imagino que você possa descobrir o que os números nos aparelhos estão fazendo.
Além disso, você pode usar delimitadores diferentes de / para seu regex. Portanto, se você precisar corresponder / não precisará escapar dela. Qualquer uma das opções abaixo é equivalente à regex no início da minha resposta. Em teoria, você pode substituir qualquer caractere pelos padrões.
perl -pe 's#(regex)#\n$1#'
perl -pe 's{(regex)}{\n$1}'
usando em -nevez de -peagir da mesma forma, mas não é impresso automaticamente no final. Pode ser útil se você quiser imprimir sozinho. Por exemplo, aqui está um grep-alike ( m/foobar/é uma correspondência de regex):
perl -ne 'if (m/foobar/) {print}'
Se você acha que lidar com novas linhas é problemático e deseja que ele seja tratado magicamente por você, adicione -l. Não é útil para o OP, que estava trabalhando com novas linhas, no entanto.
Dica de bônus - se você tiver o pacote pcre instalado, ele vem com ele pcregrep, que usa expressões regulares compatíveis com perl.
Hmm, as novas linhas que escaparam parecem funcionar em versões mais recentes do sed(eu tenho o GNU sed 4.2.1),
dev:~/pg/services/places> echo 'foobar' | sed -r 's/(bar)/\n\1/;'
Como mencionado, isso funciona com várias versões do GNU sed, mas não o sed incluído no macOS.
echo pattern | sed -E -e $'s/^(pattern)/\\\n\\1/'
funcionou bem no El Captitan com o ()apoio
Isso funcionou muito bem e você até dá um comando completo para testar e extrapolar para se especializar para o próprio propósito. Bom trabalho!
Para inserir uma nova linha no fluxo de saída no Linux, usei:
Onde file1estava:
Antes da substituição no local sed e:
Após a substituição no local sed. Observe o uso de \\\n. Se os padrões tiverem um "interior, escape usando \".
Para mim, o código acima não funciona. sedinsere em \nvez de LF porque obtém \\no parâmetro do shell. --- Este código funciona: sed -i "s/def/abc\ndef/" file1. --- GNU sed version 4.2.1, GNU bash, version 4.1.2(1) / 4.2.25(1)(versão do CentOS 6.4 / Ubuntu 12.04.3).
no sed, você pode fazer referência a grupos no seu padrão com "\ 1", "\ 2", .... portanto, se o padrão que você procura é "PATTERN" e deseja inserir "ANTES" na frente dele , você pode usar, sem escapar
sed 's/\(PATTERN\)/BEFORE\1/g'
Acabei de fazer: testfile contents = "ABC ABC ABC". Ran "sed 's / \ (ABC \) / \ n \ 1 / g' testfile, recebi as novas linhas. Experimente as escapadas, tente adicionar uma coisa de cada vez ao seu padrão, por exemplo, verifique se você está correspondendo ao teste padrão, em seguida, verificar a correspondência do grupo, em seguida, adicione a verificação de nova linha.
Eu apenas tentei exatamente isso e consegui "nabc nabc nabc' Você está usando alguma outra versão do sed.?
a fuga de conchas provavelmente está atrapalhando as tentativas de tgamblin. colocar os argumentos completos do sed em aspas simples como Steve B deve corrigir isso. É possível, porém, que versões diferentes do sed não entendam \ n para nova linha.
Você também pode fazer isso com o awk, usando -vpara fornecer o padrão:
awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file
Isso verifica se uma linha contém um determinado padrão. Nesse caso, ele anexa uma nova linha ao início.
this is some pattern and we are going ahead
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file
pattern and we are going ahead
Observe que isso afetará todos os padrões em uma linha:
this pattern is some pattern and we are going ahead
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' d
pattern is some
o que o 1 faz nisso?
@whatahitson 1é usado no Awk como uma abreviação de {print $0}. O motivo é que qualquer condição avaliada como True dispara a ação padrão do Awk, que consiste em imprimir o registro atual.
Isso funciona no MAC para mim
Dono, se é o perfeito ...
Depois de ler todas as respostas para essa pergunta, ainda me levou muitas tentativas para obter a sintaxe correta para o seguinte script de exemplo:
# script: add_domain
# using fixed values instead of command line parameters $1, $2
# to show typical variable values in this example
# no need to escape $ipaddr and $domain values if we use separate quotes.
sudo sed -i '$a \\n'"$ipaddr www.$domain $domain" /etc/hosts
O script anexa uma nova linha \nseguida por outra linha de texto ao final de um arquivo usando um único sedcomando.
\ 0 é nulo; portanto, sua expressão é substituída por nulo (nada) e depois ...
\ n é a nova linha
Em alguns sabores do Unix não funciona, mas acho que é a solução para o seu problema.
No vi da Red Hat, eu pude inserir retornos de carro usando apenas o caractere \ r. Acredito que isso execute internamente 'ex' em vez de 'sed', mas é semelhante e o vi pode ser outra maneira de fazer edições em massa, como patches de código. Por exemplo. Estou cercando um termo de pesquisa com uma instrução if que insiste em retornos de carro após as chaves: