Adicione uma sequência de prefixos ao início de cada linha


334

Eu tenho um arquivo como abaixo:

line1
line2
line3

E eu quero obter:

prefixline1
prefixline2
prefixline3

Eu poderia escrever um script Ruby, mas é melhor se eu não precisar.

prefixirá conter /. É um caminho, /opt/workdir/por exemplo.

Respostas:


527
# If you want to edit the file in-place
sed -i -e 's/^/prefix/' file

# If you want to create a new file
sed -e 's/^/prefix/' file > file.new

Se prefixcontiver /, você poderá usar qualquer outro caractere que não esteja prefixou escapar do /, para que o sedcomando se torne

's#^#/opt/workdir#'
# or
's/^/\/opt\/workdir/'

1
@ Benjaminjamin, eu já tinha votado sua resposta, no entanto, eu prefiro sedpara tarefas leves como esta. Se "prefixo" é conhecido, é muito fácil escolher um caractere que não seja "prefixo".
Alok Singhal

1
Não esqueça que você também pode usar sedem um pipeline, por exemplo foo | sed -e 's/^/x /' | bar.
zigg

1
@Dataman cool. Outra maneira seria sed -e '2,$s/^/prefix/'.
Alok Singhal

1
@BinChen escapa do /mesmo modo \/(em cadeias simples) ou \\/(em cadeias duplas) #

8
Use sed -e 's/$/postfix/' filese você deseja adicionar uma sequência ao final de cada linha.
Brian

121
awk '$0="prefix"$0' file > new_file

Com Perl (substituição no local):

perl -pi 's/^/prefix/' file

8
Com um pipe / stream ou variável:prtinf "$VARIABLE\n" | awk '$0="prefix"$0'
ThorSummoner 25/02

2
Com um arquivo grande (12 G), awkrelatórios awk: out of memory in readrec 1 source line number 1, mas a solução é sedconcluída com êxito.
JRM

33

Você pode usar o Vim no modo Ex:

ex -sc '%s/^/prefix/|x' file
  1. % selecione todas as linhas

  2. s substituir

  3. x salvar e fechar


1
Para mim, eu só abrir o arquivo no vim e tipo :%s/^/prefix/, uma vez que esta estratégia acaba por ser útil em muitas situações
Frank Bryce

23

Se o seu prefixo é um pouco complicado, basta colocá-lo em uma variável:

prefix=path/to/file/

Então, você passa essa variável e deixa o awk lidar com ela:

awk -v prefix="$prefix" '{print prefix $0}' input_file.txt


6

Usando o shell:

#!/bin/bash
prefix="something"
file="file"
while read -r line
do
 echo "${prefix}$line"
done <$file > newfile
mv newfile $file

5

Aqui está uma solução oneliner altamente legível usando o tscomando de moreutils

$ cat file | ts prefix | tr -d ' '

E como é derivado passo a passo:

# Step 0. create the file

$ cat file
line1
line2
line3
# Step 1. add prefix to the beginning of each line

$ cat file | ts prefix
prefix line1
prefix line2
prefix line3
# Step 2. remove spaces in the middle

$ cat file | ts prefix | tr -d ' '
prefixline1
prefixline2
prefixline3

'ts' não é instalado por padrão em muitas distribuições Linux. Além disso, a votação foi reduzida porque o "tr-d ''" à direita nesta resposta removerá todos os espaços das linhas, não apenas o espaço adicionado por 'ts'
Tim Bird

3

Embora eu não ache que o pierr tenha essa preocupação, eu precisava de uma solução que não atrasasse a saída do "final" ativo de um arquivo, pois queria monitorar vários logs de alerta simultaneamente, prefixando cada linha com o nome do respectivo log .

Infelizmente, sed, cut, etc. introduziram muito buffer e me impediram de ver as linhas mais atuais. A sugestão de Steven Penny de usar a -sopção de nlera intrigante, e os testes provaram que não introduziam o buffer indesejado que me preocupava.

Porém, houve alguns problemas com o uso nl, relacionados ao desejo de remover os números de linhas indesejados (mesmo que você não se importe com a estética dele, pode haver casos em que o uso de colunas extras seria indesejável). Primeiro, usar "recortar" para eliminar os números reintroduz o problema do buffer, destruindo a solução. Segundo, o uso de "-w1" não ajuda, pois isso NÃO restringe o número da linha a uma única coluna - apenas aumenta à medida que são necessários mais dígitos.

Não é bonito se você deseja capturar isso em outro lugar, mas como é exatamente isso que eu não precisava fazer (tudo estava sendo gravado nos arquivos de log, eu só queria assistir vários de uma vez em tempo real), o melhor Uma maneira de perder os números de linha e ter apenas meu prefixo era iniciar a -ssequência com um retorno de carro (CR ou ^ M ou Ctrl-M). Então, por exemplo:

#!/bin/ksh

# Monitor the widget, framas, and dweezil
# log files until the operator hits <enter>
# to end monitoring.

PGRP=$$

for LOGFILE in widget framas dweezil
do
(
    tail -f $LOGFILE 2>&1 |
    nl -s"^M${LOGFILE}>  "
) &
sleep 1
done

read KILLEM

kill -- -${PGRP}

1
use a -uopção sed para evitar o buffer.
Bryan Larsen

2
O buffer pode ser desativado com unbuffer / stdbuf, consulte unix.stackexchange.com/q/25372/6205
myroslav 4/15/15

2

Usando ed:

ed infile <<'EOE'
,s/^/prefix/
wq
EOE

Isso substitui, para cada linha ( ,), o início da linha ( ^) por prefix. wqsalva e sai.

Se a sequência de substituição contiver uma barra, podemos usar um delimitador diferente para s:

ed infile <<'EOE'
,s#^#/opt/workdir/#
wq
EOE

Eu citei o delimitador here-doc EOE("end of ed") para impedir a expansão de parâmetros. Neste exemplo, ele também não funcionaria entre aspas, mas é uma boa prática evitar surpresas se você tiver um $em seu script ed.


2

Usando & (toda a parte da entrada que correspondeu ao padrão ”):

cat in.txt | sed -e "s/.*/prefix&/" > out.txt

OU usando referências anteriores:

cat in.txt | sed -e "s/\(.*\)/prefix\1/" > out.txt

2
  1. Você também pode conseguir isso usando a técnica de backreference

    sed -i.bak 's/\(.*\)/prefix\1/' foo.txt
    
  2. Você também pode usar com o awk como este

    awk '{print "prefix"$0}' foo.txt > tmp && mv tmp foo.txt
    

1

Aqui está um exemplo embrulhado usando a sedabordagem de esta resposta :

$ cat /path/to/some/file | prefix_lines "WOW: "

WOW: some text
WOW: another line
WOW: more text

prefix_lines

function show_help()
{
  IT=$(CAT <<EOF
    Usage: PREFIX {FILE}

    e.g.

    cat /path/to/file | prefix_lines "WOW: "

      WOW: some text
      WOW: another line
      WOW: more text
  )
  echo "$IT"
  exit
}

# Require a prefix
if [ -z "$1" ]
then
  show_help
fi

# Check if input is from stdin or a file
FILE=$2
if [ -z "$2" ]
then
  # If no stdin exists
  if [ -t 0 ]; then
    show_help
  fi
  FILE=/dev/stdin
fi

# Now prefix the output
PREFIX=$1
sed -e "s/^/$PREFIX/" $FILE

2
Isso não funcionará se PREFIXhouver caracteres especiais para sed como uma barra.
Josch

Bom ponto ... Se você achar que usa muito barra, poderá usar um delimitador diferente com a parte sed, conforme detalhado aqui , o que permitiria usá-lo nas pesquisas. Outros caracteres sed especiais podem ser inseridos escapando com uma barra, por exemploprefix_lines \*
Brad Parks

0

Para as pessoas nos sistemas BSD / OSX, existe um utilitário chamado lam, abreviação de laminado. lam -s prefix filefará o que você quiser. Eu o uso em dutos, por exemplo:

find -type f -exec lam -s "{}: " "{}" \; | fzf

... que encontrará todos os arquivos, exec lam em cada um deles, dando a cada arquivo um prefixo de seu próprio nome de arquivo. (E bombeie a saída para fzf para pesquisa.)


Você está certo, parece que este é um comando apenas do BSD. O POSIX o substituiu por colar, mas colar não tem o recurso de adicionar uma sequência separadora completa. Vou atualizar minha resposta.
Raio
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.