Qual é a maneira mais fácil de adicionar uma string no início de cada linha do arquivo na linha de comando?

8

Eu estou procurando uma maneira de adicionar uma seqüência de caracteres para o início de cada linha (mesma seqüência de caracteres para cada linha). Não é algo personalizável, mas algo fácil de lembrar e disponível em todas as plataformas compatíveis com POSIX (e também em todos os shell).

sintagma
fonte

Respostas:

8

Você pode usar sed:

sed -i 's/^/your_string /' your_file

Graças aos comentários de Stephane e Marco, observe que a -iopção não é POSIX. Uma maneira POSIX de fazer o acima seria

sed 's/^/your_string /' your_file > tmp_copy && mv tmp_copy your_file

ou perl:

perl -pi -e 's/^/your_string /' your_file

Explicação

Ambos os comandos executam uma substituição de regex, substituindo o início de uma linha ( ^) pela string desejada. A -iopção nos dois comandos garante que o arquivo seja editado no local (ou seja, as alterações são refletidas no arquivo em vez de impressas no stdout).

seddeve estar disponível em qualquer sistema operacional compatível com POSIX e perlestar disponível na maioria dos Unices modernos, exceto talvez nos que passaram pelo esforço de removê-lo.

Joseph R.
fonte
1
Correção pequena: a -iopção não edita o arquivo no local. Ele cria um novo arquivo e sobrescreve o original após a conclusão (prova: o inode é alterado). Não existem muitas ferramentas que efetuem a edição no local, o que é uma operação perigosa. Além disso, como você menciona o POSIX, o -iswitch não é obrigatório para um compatível com POSIX sed, é um recurso de algumas implementações específicas.
Marco
2
sed -inão é POSIX. É o GNU. O FreeBSD sedtem uma opção semelhante, mas você precisa de sed -i ''lá.
Stéphane Chazelas
@Marco Estou ciente de que -icria uma cópia temporária (é por isso que eu disse que as alterações são refletidas no arquivo original); Eu quis dizer que você obtém a mesma semântica que a substituição no local. Verifique se a resposta atualizada é compatível com POSIX.
Joseph R.
A rigor, as alterações são refletidas em um novo arquivo com o mesmo nome que o original.
Keith Thompson
1
Costumo usar $$(o ID do processo do shell atual) como parte de um nome de arquivo temporário; evita o esforço de pensar em um nome único garantido sempre:command filename > filename.$$ && mv filename.$$ filename
Keith Thompson
14
:|paste -d'foo ' - - - - input > output

(Brincadeirinha, embora você provavelmente descubra que é a mais rápida de todas as soluções postadas aqui: -b).

O caminho canônico é:

sed 's/^/foo /' < input > output

No entanto, não é facilmente adaptável a seqüências arbitrárias. Por exemplo,

sed "s/^/$var /"

Só funciona se $varnão contém, &, \, /nem caracteres de nova linha.

Nesse sentido,

export var
awk '{print ENVIRON["var"], $0}'

ou

perl -pe '$_="$ENV{var} $_"'

funcionaria melhor.

Stéphane Chazelas
fonte
isso é algo interessante ...: P
Rahul Patil
4

Apresento uma solução usando o awkprefixo "foo".

awk '{ print "foo", $0; }' input > output

awké multiplataforma e está disponível em qualquer sistema POSIX. Não realiza edição no local. Se você deseja editar um arquivo sem criar um segundo, precisará usar um arquivo temporário. Veja a sedresposta de Joseph , mostra a sintaxe. Outro truque é usar a seguinte sintaxe, que basicamente cria um arquivo temporário com o mesmo nome que o arquivo original.

{ rm file; awk '{ print "foo", $0 }' > file; } < file
Marco
fonte
reducto# wc -l foo914 foo` reducto# { rm foo ; awk '{ print "prepend" , $0 }' > foo } < foo >Isso parece não funcionar. Eu estava tentando, porque o redirecionamento para o original me deixou nervoso, mas nem sequer começou.
Kurtm
1
Este exemplo funcionará se ele usar parênteses para o exterior, em vez de chaves.
Kurtm # 8/13
4

Você pode evitar os problemas de edição no local com as ferramentas de fluxo usando uma ferramenta que normalmente faz a edição no local - um editor!

ex sample.txt -c "%s/^/foo /" -c wq

Há uma vantagem adicional de que os comandos são fáceis e óbvios para quem é versado no único editor verdadeiro.

Mike DeAngelo
fonte
2

Você pode usar perlpara fazer isso:

$ perl -pi -e 's/^/mystring /' afile.txt

Exemplo

Crie um arquivo de amostra.

$ seq 5 > afile.txt

$ cat afile.txt
1
2
3
4
5

Execute o comando acima:

$ perl -pi -e 's/^/mystring /' afile.txt

$ cat afile.txt
mystring 1
mystring 2
mystring 3
mystring 4
mystring 5
slm
fonte
Perl parece ser universal hoje em dia, mas por um longo tempo não foi. E aposto que existem algumas variantes raras do UNIX por aí que se recusam firmemente a ter o perl como parte da base. Algo para estar ciente.
Kurtm
@kurtm veja a discussão aqui . Aparentemente, o AIX não possui Perl por padrão e nem sistemas incorporados.
terdon
2
@ DavidSainty - é universal o suficiente. O Q foi marcado com o Bash, então acho extremamente difícil imaginar um sistema que tenha o Bash, mas não o Perl. De qualquer forma, aqui está uma das 5 respostas, várias das outras mostram como usar sed, eu mostrei como usar Perl .... não procurando uma guerra santa sobre o assunto.
slm
1
@DavidSainty Aparentemente apenas o OpenBSD. Acho que assumi que o pessoal do Open tende a ser conservador quanto ao que eles permitem na base. O OpenBSD definitivamente o possui na base.
kurtm
1
@slm: " Acho extremamente difícil imaginar um sistema que tenha o Bash, mas não o Perl ". Eu tenho vários desses sistemas em minha mesa. (Eles são sistemas embarcados.)
Keith Thompson
1

Simplesmente usando o Bash

 while IFS= read -r line; do echo "foo" "${line}" ; done  < input > Output

Usando Python

python -c "import sys; print 'foo '.join([ l for l in sys.stdin.readlines() ])" < input > Output

Se você deseja editar no local

import fileinput
import sys

for line in fileinput.input(['inputfile'], inplace=True):
    sys.stdout.write('foo {l}'.format(l=line))

Link de referência

Rahul Patil
fonte
Por que está funcionando mais rápido que o awk?
Rahul Patil
1
Só vai funcionar mais rápido do que awkem arquivos muito pequenos. O comportamento varia nas implementações de eco e elimina os espaços em branco iniciais e finais e processa as barras invertidas especialmente.
Stéphane Chazelas
@StephaneChazelas Yes. você está 100% correto apenas testado ... paste.ubuntu.com/6210934
Rahul Patil
prefix () { while IFS= read -r REPLY; do printf "%s%s\n" "$1" "$REPLY"; done; }deveria ser mais correto.
Matt
1
Por que o {}? Eu acho que o @Matt estava sugerindo que você transformasse em uma função nomeada, qual é o sentido de {}sem um nome de função?
terdon
-1

Ou você pode fazer o seguinte:

vi filename.txt

Esc(para garantir que você esteja no NORMALmodo) e digite o seguinte comando:

:1,$ s/^/mystring
Dino
fonte
Observe que, como o usuário está perguntando sobre todas as linhas do arquivo, você pode substituir 1,$ por simplesmente %. Isso faz o comando :%s/^/string/.
precisa saber é o seguinte