テキスト処理-2行ごとにコンマで結合します


35

ファイルに1000行以上あります。ファイルは次のように始まります(行番号が追加されます):

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

これをファイルに変換する必要があります。2行ごとに結合して、コンマ区切りのエントリにします。最終的なデータは次のようになります

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

私がやろうとしていたのは、シェルスクリプトを記述してから、echoそれらの間にカンマを入れようとすることでした。しかし、よりシンプルで効果的なワンライナーがsed/にあるかもしれませんawk

何か案は?


@ l0b0行番号は「説明のためだけにある」というOPのコメントを編集しました
...-jasonwryan

@jasonwryan申し訳ありませんが、説明のためにがあると思いました。行0の解析エラー
l0b0

回答:


39

単にcat(猫が好きなら;-))とpaste

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

説明:paste多数のファイルから読み取り、対応する行(最初のファイルの1行目と2番目のファイルの1行目など)を貼り付けます。

paste file1 file2 ...

ファイル名の代わりに、-(ダッシュ)を使用できます。pastefile1(stdin)から最初の行を取得します。次に、file2(stdinでもあります)から最初の行を読み取ります。ただし、stdinの最初の行は既に読み取られて処理されているため、入力ストリームで待機するのはstdin の2であり、これpasteが最初の行にうまく接着します。この-dオプションは、区切り文字をタブではなくコンマに設定します。

または、行う

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

PSはい、上記を単純化して

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

または

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

これにはを使用しないという利点がありcatます。

ただし、わかりやすくするために、このイディオムを意図的に使用しませんでした-冗長性が低く、好きですcat(CATS ARE NICE)。だから編集しないでください。

あるいは、猫に貼り付けたい場合(貼り付けはファイルを水平に連結するコマンドですが、猫はファイルを垂直に連結します)、次のように使用できます。

paste file.in | paste -d, - -

もう一度申し上げます。行番号はファイルの一部ではありません:)
mtk

paste コマンドは完璧に動作、あなたはそれについてもう少し説明をお願いすることができます。ハイフン???
mtk

2
ハイフンは「stdinから読み取る」ことを意味します。同じ入力ソースが繰り返される場合、貼り付けは出力の行ごとに数回それから読み取ることを知っています。
-dubiousjim

@ sch:クールな編集、私はそれに触れません:

1
あなたのcat議論に関して。動作しsed "N;s/\n/,/" file.in > file.outませんか?
ベルンハルト


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

sedを使用して、2行ごとにjoin(N)し、newline(\ n)を「、」に置き換えます。


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

また、単に1つの文字を別の文字(他のすべての改行をコンマに置き換える)に置き換えているだけなので、入力ファイルを適切に処理できることに注意してください。

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

(ただし、一部のエミュレートされたPOSIX pasteが非UNIX方式で処理する可能性があるCRLFターミネータ(Microsoftのような)がある非UNIXシステムでは動作しない可能性があることに注意してください)


1ここで何をしているの1<>?それはタイプミスですか?
αғsнιη

@αғsнιηは、参照この
iruvar

@iruvarはあなたに感謝
αғsнιη

2

これは、純粋なBashを使用した1行(ただし、潜在的に数百万のコマンド実行者)です。

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

私はサブシェル(paranthesis)を使用しているので、保存および復元する必要はありませんIFS。そうでなければ、ソースがソースされている場合にユーザー環境を台無しにしないようにするためにどれをすべきか。代替だけにその新しいIFSを渡すことであろうreadのようにIFS= read -r nameIFS= read -r code

ループ内のすべてのコマンドがシェルに組み込まれているという事実は、そのパフォーマンスを許容できるものにし、小さなファイル用の他のソリューションよりもさらに高速です。しかし、多くの人はそれを悪い習慣だと考えているでしょうし、他の何かに一般化するときは注意が必要です。


一般に、サブシェルを使用して環境の変更をローカライズすることは賛成です。ただし、この場合は不要です。代わりに行うことができますwhile IFS='\n' read -r name; do IFS='\n' read -r code ... done < file.in。これは、シェルスクリプトでよく見られるイディオムです。-rフラグread手段「の文字に続く文字を『\』解釈『n』の2つの文字として標準入力ストリームではなく、改行など。」間違いなく、サブシェルを作成する方が、を繰り返すよりも美的かもしれませんIFS='\n'
-dubiousjim

@dubiousjim:-r技術的にソリューションを改善しました。すばらしいです!私は、変更されたものをIFS2回渡すというアイデアは好きではありません。1回の読み取りを使用していた場合、非常に便利ですが、2回は使用しませんでした。もちろん、それは意見の問題です。サブシェルの使用は、私が言う一般的なBashの知識を少し超えているため、多くの人がその目的を理解するのに苦労するでしょう。それは悪いことです。
削除

2

回答の完全なセットについて、考えられるawk解決策は次のとおりです。

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

@downvoter:ダウンボートに値する私の答えの何が問題になっていますか?どのように改善できますか?
ベルンハルト

たぶん怠becauseだからprintf?まれに、ステーション名にフォーマット指定子が含まれる場合に失敗します。(参照pastebin.com/wgxFttrJ例えば。)しかし、これは単なる推測ですが、downvoteは私からではありません。
マナトワーク

1

awkイディオムの白髪の古い栗

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'短くてイディオム
クオンルム

@cuonglm、私はそれを疑います。この例でprintは、意図が明確であるにもかかわらず、まだワンライナーです。私のような1古いawkprint
にとって

これは、2行以上に簡単に設定できる最初のシンプルなソリューションでした。sed検索する前にしばらくの間戦っていましたがawk、4行ごとの結合を簡単にしました。への旅を救ってくれました$EDITOR
-opello


0

例えば:

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

出力:(注: xargs -L number_of_columns2行ごとではなく、ほとんどの列でうまく動作します)

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.