Processamento de texto - junte-se a cada duas linhas com vírgulas

31

Eu tenho mais de 1000 linhas em um arquivo. O arquivo começa da seguinte maneira (números de linha adicionados):

Station Name
Station Code
A N DEV NAGAR
ACND
ABHAIPUR
AHA
ABOHAR
ABS
ABU ROAD
ABR

Eu preciso converter isso em um arquivo, com entradas separadas por vírgula unindo todas as duas linhas. Os dados finais devem se parecer com

Station Name,Station Code
A N DEV NAGAR,ACND
ABHAIPUR,AHA
ABOHAR,ABS
ABU ROAD,ABR
...

O que eu estava tentando era - tentar escrever um script de shell e, em seguida, echo com vírgula entre eles. Mas eu acho que um one-liner efetivo mais simples faria o trabalho aqui pode estar em sed / awk .

Alguma idéia?

    
por mtk 17.10.2012 / 19:41

10 respostas

32

Basta usar cat (se você gosta de gatos ;-)) e paste :

cat file.in | paste -d, - - > file.out

Explicação: paste lê um número de arquivos e cola as linhas correspondentes (linha 1 do primeiro arquivo com a linha 1 do segundo arquivo etc):

paste file1 file2 ...

Em vez de um nome de arquivo, podemos usar - (traço). paste recebe a primeira linha do arquivo1 (que é stdin). Então, ele quer ler a primeira linha do arquivo2 (que também é stdin). No entanto, como a primeira linha de stdin já foi lida e processada, o que agora aguarda no fluxo de entrada é a linha segundo do stdin, que paste colou alegremente no primeiro. A opção -d define o delimitador como uma vírgula em vez de uma guia.

Alternativamente, faça

cat file.in | sed "N;s/\n/,/" > file.out

P.S. Sim, pode-se simplificar o acima para

< file.in sed "N;s/\n/,/" > file.out

ou

< file.in paste -d, - - > file.out

que tem a vantagem de não usar cat .

No entanto, eu não usei esse idioma de propósito , por motivos de clareza - é menos detalhado e eu gosto de cat (CATS ARE NICE). Então, por favor, não edite.

Como alternativa, se você preferir colar a gatos (colar é o comando para concatenar arquivos horizontalmente, enquanto o gato concatena na vertical), você pode usar:

paste file.in | paste -d, - -
    
por 17.10.2012 / 19:54
6

Caso alguém desembarque pretenda combinar todas as linhas em um liner CSV, tente

cat file | tr '\n' ','
    
por 22.01.2014 / 22:15
3
sed 'N;s/\n/,/' file

Usando sed, junte-se (N) a cada 2 linhas e substitua a nova linha (\ n) por ",".

    
por 18.10.2012 / 04:17
3
paste -sd ',\n' file.in > file.out

Observe também que, como estamos apenas substituindo um caractere por outro (cada outra nova linha com vírgula), podemos trabalhar no arquivo de entrada:

paste -sd ',\n' file.in 1<> file.in

(mas cuidado, pode não funcionar em sistemas não-Unix que têm terminadores CRLF (como os da Microsoft) que alguns emulam POSIX paste podem tratar de uma maneira não-Unix)

    
por 17.10.2012 / 20:11
2

Aqui está um one-liner (embora potencialmente milhões de comandos-run-er) usando Bash puro:

(IFS=; while read -r name; do read -r code; printf '%s\n" "$name,$code"; done < file.in) > file.out

Eu uso um subshell (a parantesia) para não precisar armazenar e restaurar IFS . Que caso contrário deveria fazer para não atrapalhar o ambiente dos usuários caso a origem seja originada. A alternativa seria passar esse novo IFS apenas para read como em IFS= read -r name , IFS= read -r code .

O fato de que todos os comandos no loop são construídos no shell torna seu desempenho aceitável e é ainda mais rápido do que as outras soluções para arquivos pequenos. Mas muitas pessoas considerariam isso uma prática ruim e deve-se ter cuidado ao generalizá-lo para qualquer outra coisa.

    
por 17.10.2012 / 20:25
2

Para o conjunto completo de respostas, uma possível solução awk pode ser:

awk 'NR%2==1 {printf $0","} NR%2==0 { print $0}' *file*
    
por 18.10.2012 / 13:11
1

Castanha velha e grossa de um awk idiom

awk '{ORS=NR%2?",":"\n";print}' file
Station Name,Station Code
A N DEV NAGAR,ACND
ABHAIPUR,AHA
ABOHAR,ABS
ABU ROAD,ABR
    
por 29.08.2015 / 02:38
0

Possível com o perl também,

perl -pe 's/^\d+\.\s+//;$.&1?chomp:print","' file

    
por 18.10.2012 / 02:40
0

Por exemplo:

seq 0 70 | xargs -L 2 | sed 's/ /,/g'

Saída: (nota: xargs -L number_of_columns funciona bem com a maioria de qualquer número de colunas, não apenas a cada duas linhas)

0,1
2,3
4,5
6,7
8,9
10,11
12,13
14,15
16,17
18,19
20,21
22,23
24,25
26,27
28,29
30,31
32,33
34,35
36,37
38,39
40,41
42,43
44,45
46,47
48,49
50,51
52,53
54,55
56,57
58,59
60,61
62,63
64,65
66,67
68,69
70
    
por 25.10.2016 / 19:40
0

Solução POSIX com pr :

pr -2 -a -t -s, file

link

    
por 19.05.2018 / 03:57