Metin işleme - her iki satıra da virgülle katılın


35

Bir dosyada 1000'den fazla satır var. Dosya aşağıdaki gibi başlar (satır numaraları eklendi):

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

Her iki satıra katılarak virgülle ayrılmış girişlerle bunu bir dosyaya dönüştürmem gerekiyor. Son veriler şöyle görünmeli

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

Çalıştığım şey - bir kabuk betiği ve sonra echoaralarında virgülle yazmaya çalışmaktı . Fakat sanırım daha basit ve etkili bir tek gömlek bu işi yapabilir sed/ içinde olabilir awk.

Herhangi bir fikir?


@ l0b0 OP'nin satır numaralarının "sadece açıklama için var" olduğu
yönündeki notunu düzenlediniz

Maalesef @jasonwryan, diye düşündüm hatları açıklama için vardı. 0 satırında ayrıştırma hatası
l0b0

Yanıtlar:


39

Basitçe kullanın cat(eğer kedileri seviyorsanız ;-)) ve paste:

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

Açıklama: pastebirkaç dosyadan okur ve karşılık gelen satırları birbirine yapıştırır (satır 1'den ilk dosyadan satır 1 ile ikinci dosyadan vb.):

paste file1 file2 ...

Bir dosya adı yerine, -(tire) kullanabiliriz . pasteilk satırı file1'den alır (stdin). Ardından, ilk satırı file2'den okumak ister (aynı zamanda stdin). Bununla birlikte, stdin'in ilk satırı zaten okundu ve işlendiğinden, giriş akışında şu an beklediği şey, ilk önce mutlu bir şekilde yapıştırılan stdin'in ikinci satırıdır paste. -dSeçenek virgül yerine bir sekme olması sınırlayıcı ayarlar.

Alternatif olarak, yapmak

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

Ps evet, bir yukarıdaki için basitleştirebilirsiniz

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

veya

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

kullanmama avantajına sahiptir cat.

Ancak, bu deyimi bilerek kullanmamıştım , açıklık nedenleriyle - daha az ayrıntılı ve hoşuma gidiyor cat(CATS ARE NICE). Lütfen düzenleme yapmayın.

Alternatif olarak, kedilere yapıştırmayı tercih ederseniz (yapıştırma, dosyaları yatay olarak birleştirmenin komutudur, cat bunları dikey olarak birleştirirken), şunları kullanabilirsiniz:

paste file.in | paste -d, - -

Sadece tekrar söylemek istiyorum. Satır numaraları dosyanın bir parçası değil :)
mtk

paste Komut mükemmel bu konuda biraz daha açıklama veriniz olabilir, çalışır. Tire'ler ???
mtk

2
Tire işaretleri "stdin'den okumak" anlamına gelir. Aynı giriş kaynağı tekrarlanırsa, yapıştır, çıkış satırı başına birkaç kez okumayı bilir.
dubiousjim

@sch: cool edit, dokunmayacağım :-)
Ocak

1
Sizin ile ilgili olarak catargüman. Mu sed "N;s/\n/,/" file.in > file.outçalışmıyor?
Bernhard

8

Buraya inen birinin tüm çizgileri CSV bir astar olarak bir araya getirmesi isteniyorsa, deneyin

cat file | tr '\n' ','

3
sed 'N;s/\n/,/' file

Sed kullanarak, her 2 satıra (N) katılın ve yeni satırı (\ n) "," ile değiştirin.


3
paste -sd ',\n' file.in > file.out

Ayrıca, yalnızca bir karakteri bir başkasıyla değiştirdiğimizden (diğer her virgül virgülle yazdığımız için) giriş dosyasında yerinde çalışabileceğimize dikkat edin:

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

(ancak bazı öykünmüş POSIX’in pasteUnix olmayan bir şekilde davranabileceği CRLF sonlandırıcısına sahip Unix olmayan sistemlerde (Microsoft’lar gibi ) çalışmayabileceğini unutmayın)


Bunun 1burada ne işi var 1<>? bu bir yazım hatası mı?
αғsнιη

@ αғsнιη, bunu gör
iruvar

@iruvar thank you
αғsнιη

2

Saf Bash kullanan bir liner (potansiyel olarak milyonlarca emir-run-er):

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

Saklamak ve geri yüklemek zorunda kalmamam için bir alt kabuk (parantez) kullanıyorum IFS. Aksi halde, kaynak kaynaklı olması durumunda kullanıcı ortamını karıştırmamak için yapılması gerekenler. Alternatif sadece o yeni IFS geçmek olacaktır readolduğu gibi IFS= read -r name, IFS= read -r code.

Döngüdeki tüm komutların kabuk içine yerleştirilmiş olması, performansını kabul edilebilir kılar ve küçük dosyalar için diğer çözümlerden daha hızlıdır. Ancak birçok insan bunun kötü bir uygulama olduğunu düşünür ve bir şeyi başka bir şeye genellendirirken dikkatli olunmalıdır.


genel olarak ortam değişikliklerini yerelleştirmek için alt kabuk kullanmak için yay. Ancak bu durumda gerekli değildir: bunun yerine while IFS='\n' read -r name; do IFS='\n' read -r code ... done < file.in, kabuk komut dosyalarında sıklıkla gördüğüm bir deyimdir. -rİçin bayrak readaracı "karakterini '\' yerine bir yeni satır olarak ikiden karakter olarak Stdin akışında karakteri 'n' izledi yorumlamak." Muhtemelen, alt kabuğunu oluşturmak, yaptığınız gibi tekrarlamaktan daha estetik olabilir IFS='\n'.
dubiousjim

@dubiousjim: -rÇözümü teknik olarak iyileştirdi. Harika! IFSİki kere değişme fikrinin hayranı değilim . Bir tane okumuş olsaydım, süper güzeldi, ama iki kere değil. Tabii ki bu bir fikir meselesi . Bir alt kabuk kullanmak, söyleyeceğim genel Bash bilgisinin biraz üzerindedir, bu yüzden birçok insan amacını anlamakta zorlanacaktır. Bu kötü bir şey.
silinmiş

2

Tüm cevaplar için olası bir awkçözüm olabilir:

awk 'NR%2==1 {printf $0","} NR%2==0 { print $0}' *file*

@ downvoter: Bir yanıt vermeyi hak etme cevabımın nesi yanlış? nasıl geliştirilebilir?
Bernhard

Belki de tembel printf? Bir istasyon adı bir format belirteci içerdiğinde nadir durumlarda başarısız olur. ( Bir örnek için pastebin.com/wgxFttrJ adresine bakın .) Fakat bu sadece bir tahmin, en önemlisi benden değil.
Manatwork

1

Bir awkdeyim hoary eski kestane

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

awk '{ORS=NR%2?",":"\n"};1'daha kısa ve daha deyimdir
cuonglm

@ cuonglm, bundan şüpheliyim. Bu örnekte print, niyetim net olmasına rağmen hala tek bir gömlek var . 1tıpkı awkkendim gibi yaşlı ellerde olduğu kadar net ama ben tercih ediyorumprint
iruvar

Bu, 2 satırdan fazla için kolayca yapılandırılabilir bulduğum ilk basit çözümdü. sedArama yapmadan önce bir süre savaştım , ancak awkher 4 çizgiyi birleştirmeyi daha kolay hale getirdim . Beni bir gezi kurtardı $EDITOR!
opello

0

Perl ile de mümkün

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


0

Örneğin:

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

Çıktı: (not: xargs -L number_of_columnsyalnızca her iki satırda değil, çoğu sütunla iyi çalışır)

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.