Insira uma linha no número de linha específico com sed ou awk

146

Eu tenho um arquivo de script que preciso modificar com outro script para inserir um texto na 8ª linha.

String para inserir:, Project_Name=sowstestem um arquivo chamado start.

Tentei usar awk e sed, mas meu comando está ficando distorcido.

ashok
fonte

Respostas:

231
sed -i '8i8 This is Line 8' FILE

insere na linha 8

8 This is Line 8

no arquivo FILE

-i faz a modificação diretamente no arquivo FILE, sem saída para o stdout, conforme mencionado nos comentários de glenn jackman.

Usuário desconhecido
fonte
3
Sim, a opção -i é específica para o GNU-sed.
usuário desconhecido
1
Não. -I significa "modificar o arquivo especificado no local". A inserção vs. anexar é obtida com '8isomething' vs. '8asomething', independente da opção -i.
usuário desconhecido
11
usuários de mac: com homebrew brew install gnu-sede , em seguida, use-o comgsed
cwd
4
Isso é super útil! Existe alguma maneira para eu inserir espaços no início da linha? Notei sed não está prestando atenção ao espaço em branco inicial ...
elju
9
@elju: Sim, mascará-lo com uma barra invertida: sed '8i\ 8 This is Line 8' FILE.
usuário desconhecido
32

Uma edresposta

ed file << END
8i
Project_Name=sowstest
.
w
q
END

.em sua própria linha termina o modo de entrada; wescreve; qsai. O GNU ed tem um wqcomando para salvar e sair, mas os antigos não.

Leitura adicional: https://gnu.org/software/ed/manual/ed_manual.html

Glenn Jackman
fonte
19

OS X / macOS / FreeBSD sed

A -iflag funciona de maneira diferente no macOS sede no GNU sed.

Aqui está a maneira de usá-lo no macOS / OS X:

sed -i '' '8i\
8 This is Line 8' FILE

Veja man 1 sedpara mais informações.

Mateusz Piotrowski
fonte
18

a resposta awk

awk -v n=8 -v s="Project_Name=sowstest" 'NR == n {print s} {print}' file > file.new
Glenn Jackman
fonte
@ Jackman Jennifer eu preciso entrar #define SERVER@"http://10.35.42.54/ms0.8"para uma linha específica. Como posso conseguir isso?
Nevin Raj Victor
1
Eu acho que Nevin só precisa escapar as aspas em sua string com barras invertidas
Chris Koknat
@waLLe, comece com a página de informações do awk, que possui uma boa descrição de como o awk funciona. Aqui, eu tenho 2 pares "condition {action}", o segundo não tem condição, o que significa que a ação é executada para cada registro. Depois de terminar de ler e ainda tiver dúvidas, entre em contato.
Glenn Jackman
@glennjackman quase lá .. só não consegui isso: arquivo> arquivo.new
w411 3/11
"arquivo" representa o nome do arquivo em que o awk está trabalhando. >é o símbolo de redirecionamento do shell, para que a saída do awk seja armazenada no arquivo chamado "file.new".
Glenn Jackman
16

O POSIX sed(e, por exemplo, OS X sed, sedabaixo) precisa iser seguido por uma barra invertida e uma nova linha. Além disso, pelo menos o OS X sednão inclui uma nova linha após o texto inserido:

$ seq 3|gsed '2i1.5'
1
1.5
2
3
$ seq 3|sed '2i1.5'
sed: 1: "2i1.5": command i expects \ followed by text
$ seq 3|sed $'2i\\\n1.5'
1
1.52
3
$ seq 3|sed $'2i\\\n1.5\n'
1
1.5
2
3

Para substituir uma linha, você pode usar os comandos c(alterar) ou s(substituir) por um endereço numérico:

$ seq 3|sed $'2c\\\n1.5\n'
1
1.5
3
$ seq 3|gsed '2c1.5'
1
1.5
3
$ seq 3|sed '2s/.*/1.5/'
1
1.5
3

Alternativas usando awk:

$ seq 3|awk 'NR==2{print 1.5}1'
1
1.5
2
3
$ seq 3|awk '{print NR==2?1.5:$0}'
1
1.5
3

awkinterpreta barras invertidas em variáveis ​​passadas com -vmas não em variáveis ​​passadas usando ENVIRON:

$ seq 3|awk -v v='a\ba' '{print NR==2?v:$0}'
1
a
3
$ seq 3|v='a\ba' awk '{print NR==2?ENVIRON["v"]:$0}'
1
a\ba
3

Ambos ENVIRONe -vsão definidos pelo POSIX.

Lri
fonte
7

Soluções Perl:

rapido e sujo:

perl -lpe 'print "Project_Name=sowstest" if $. == 8' file

  • -l retira as novas linhas e as adiciona novamente, eliminando a necessidade de "\ n"
  • -p loops sobre o arquivo de entrada, imprimindo todas as linhas
  • -e executa o código entre aspas simples

$. é o número da linha

equivalente à solução awk de @ glenn, usando argumentos nomeados:

perl -slpe 'print $s if $. == $n' -- -n=8 -s="Project_Name=sowstest" file

  • -s permite um analisador de argumento rudimentar
  • -- impede que -n e -s sejam analisados ​​pelo analisador de argumentos perl padrão

argumentos de comando posicional:

perl -lpe 'BEGIN{$n=shift; $s=shift}; print $s if $. == $n' 8 "Project_Name=sowstest" file

variáveis ​​ambientais:

setenv n 8 ; setenv s "Project_Name=sowstest"
echo $n ; echo $s
perl -slpe 'print $ENV{s} if $. == $ENV{n}' file

ENV é o hash que contém todas as variáveis ​​de ambiente

Getopt para analisar argumentos em hash% o:

perl -MGetopt::Std -lpe 'BEGIN{getopt("ns",\%o)}; print $o{s} if $. == $o{n}' -- -n 8 -s "Project_Name=sowstest" file

Getopt :: Nomes de opção longos e longos

perl -MGetopt::Long -lpe 'BEGIN{GetOptions(\%o,"line=i","string=s")}; print $o{string} if $. == $o{line}' -- --line 8 --string "Project_Name=sowstest" file

Getopt é a solução de biblioteca padrão recomendada.
Isso pode ser um exagero para scripts perl de uma linha, mas pode ser feito

Chris Koknat
fonte
2
Parabéns a você, Chris, por dedicar um tempo para explicar tudo isso e colocá-lo de maneira tão agradável, mas uau, é por isso que eu não gosto de perl.
rsaw
5

Para aqueles que estão no SunOS que não é GNU, o seguinte código ajudará:

sed '1i\^J
line to add' test.dat > tmp.dat
  • ^ J é inserido com ^ V + ^ J
  • Adicione a nova linha após '1i.
  • \ DEVE ser o último caractere da linha.
  • A segunda parte do comando deve estar em uma segunda linha.
Nasri Najib
fonte
5

sed -e '8iProject_Name=sowstest' -i start usando GNU sed

Exemplo de execução:

[root@node23 ~]# for ((i=1; i<=10; i++)); do echo "Line #$i"; done > a_file
[root@node23 ~]# cat a_file
Line #1
Line #2
Line #3
Line #4
Line #5
Line #6
Line #7
Line #8
Line #9
Line #10
[root@node23 ~]# sed -e '3ixxx inserted line xxx' -i a_file 
[root@node23 ~]# cat -An a_file 
     1  Line #1$
     2  Line #2$
     3  xxx inserted line xxx$
     4  Line #3$
     5  Line #4$
     6  Line #5$
     7  Line #6$
     8  Line #7$
     9  Line #8$
    10  Line #9$
    11  Line #10$
[root@node23 ~]# 
[root@node23 ~]# sed -e '5ixxx (inserted) "line" xxx' -i a_file
[root@node23 ~]# cat -n a_file 
     1  Line #1
     2  Line #2
     3  xxx inserted line xxx
     4  Line #3
     5  xxx (inserted) "line" xxx
     6  Line #4
     7  Line #5
     8  Line #6
     9  Line #7
    10  Line #8
    11  Line #9
    12  Line #10
[root@node23 ~]# 
não
fonte
De onde vem a trilha $na linha 3 após a inserção?
JWW
É da -Abandeira para cat:)
jno 27/10
e se a string que você deseja inserir contiver aspas, parênteses etc.?
Anentropic
Veja atualização para o texto acima. Isso significa que você terá que escapar desses caracteres, conforme apropriado.
jno
0

sed -i "" -e $ '4 a \\ n''Project_Name = sowstest' start

  • Esta linha funciona bem no macOS
Elza James
fonte