Adicionando uma coluna de valores em um arquivo delimitado por tabulação

17

Como posso adicionar uma coluna de valores em um arquivo que possui um certo número de linhas. Eu tenho um arquivo de entrada como este:

Arquivo de entrada:

SPATA17 1   217947738
LYPLAL1 1   219383905
FAM47E  4   77192838
SHROOM3 4   77660162
SHROOM3 4   77660731
SHROOM3 4   77662248

Arquivo de saída:

SPATA17 1   217947738 file1
LYPLAL1 1   219383905 file1
FAM47E  4   77192838  file1
SHROOM3 4   77660162  file1
SHROOM3 4   77660731  file1
SHROOM3 4   77662248  file1

Nesse caso, quero adicionar uma coluna de valores, até o número de linhas no arquivo. O valor permanece consistente, como "arquivo1".

O motivo é que eu tenho 100 desses arquivos. Não quero abrir cada arquivo e colar uma coluna. Também existe alguma maneira de automatizar isso, entrando em um diretório e adicionando uma coluna de valores. O valor vem do nome do arquivo, que deve ser adicionado em cada linha do arquivo na última / primeira coluna.

Ron
fonte

Respostas:

22

Você pode usar um loop de uma linha como este:

for f in file1 file2 file3; do sed -i "s/$/\t$f/" $f; done

Para cada arquivo da lista, isso será usado sedpara anexar ao final de cada linha uma guia e o nome do arquivo.

Explicação:

  • Usando o -isinalizador com sedpara executar uma substituição no local, substituindo o arquivo
  • Realize uma substituição com s/PATTERN/REPLACEMENT/. Neste exemplo, PATTERN é $o final da linha e REPLACEMENT é \t(= a TAB) e $fé o nome do arquivo da variável de loop. O s///comando está entre aspas duplas para que o shell possa expandir variáveis.
janos
fonte
O código funciona. Você pode explicar o conteúdo entre aspas?
Ron
Assim como o "awk" é usado durante o trabalho com colunas, o 'sed' também é usado para situações semelhantes. Sou novato em 'awk' e 'sed'.
Ron
O @Ron sedé mais prático para substituição de padrões e economia no local. Para sua exigência de salvar o arquivo, era uma opção relativamente conveniente. Se você não precisar gravar novamente no mesmo arquivo que está processando, awkgeralmente será muito mais fácil trabalhar com ele.
janos 28/02
Pessoalmente, sou enganado pelos awkseparadores de campo de entrada / saída com muita frequência e, portanto, tento evitar usá-lo sempre que possível, tornando-o sedmais atraente.
usar o seguinte comando
11

Vamos lá, por que vocês recomendam essas ferramentas poderosas quando há pastecomando!

$ cat a
A
B
C
D
$ cat b
1
2
3
4
$ paste a b
A   1
B   2
C   3
D   4

Com um pouco de truque, você pode usar pastepara o objetivo do OP. No entanto, ele não substituirá os arquivos no local:

for f in file1 file2 file3; do 
    paste $f <(yes $f | head -n $(cat $f | wc -l)) > $f.new
done

Isso irá colar o nome do arquivo respectivo como a última coluna de cada arquivo no novo arquivo filename.new

yegle
fonte
Obrigado! pasteé certamente uma jóia escondida.
N
10

Você pode usar awk:

awk '{print $0, FILENAME}' file1 file2 file3 ...
cuonglm
fonte
Como cada arquivo possui um nome diferente, é necessário fazer isso 100 vezes. Existe alguma maneira de fazer isso uma vez?
Ron
Não, FILENAMEé uma variável awk, ela se expande para o nome do arquivo atual que awkestá sendo processado. Você apenas faz um, alimenta todos os arquivos para awk.
cuonglm
ok, mas como direcionar a saída para um novo arquivo, de cada arquivo? o awk armazena cada arquivo durante o processamento?
Ron
Se você tiver GNU awk 4.1.0ou mais tarde, poderá usar -ipara editar no local. Caso contrário, você deve redirecionar a awksaída para um arquivo temporário e usá-lo greppara extrair a linha de cada arquivo.
cuonglm
Bem, você pode fazerfor file in *; do awk 'BEGIN{OFS="\t"}{print $0, FILENAME}' $file; done
fedorqui