やりたいこと
入力 (標準入力)
stdin
A
B
C
D
E
F
出力 (標準出力)
stdout
A,B,C
D,E,F
結論
こちで回答したもの。
https://superuser.com/a/1738053/1722949
$ cat split.sh
#!/bin/bash -x
<input.txt pr -3tas,
<input.txt paste -d, - - -
<input.txt awk 'ORS=NR%3?",":"\n"'
<input.txt perl -pe'$.%3&&s/\n/,/'
<input.txt split -l3 --filter=paste\ -sd,
<input.txt perl -l0pe '$_.=$.%3?",":"\n"'
$ ./split.sh
+ pr -3tas,
A,B,C
D,E,F
+ paste -d, - - -
A,B,C
D,E,F
+ awk 'ORS=NR%3?",":"\n"'
A,B,C
D,E,F
+ perl '-pe$.%3&&s/\n/,/'
A,B,C
D,E,F
+ split -l3 '--filter=paste -sd,'
A,B,C
D,E,F
+ perl -l0pe '$_.=$.%3?",":"\n"'
A,B,C
D,E,F
解説
<input.txt
コマンドの標準入力に input.txt を流し込む (リダイレクト)。
リダイレクトはどこにあってもいい。
以下は等価 (サブプロセス起動とかで厳密には違う)
$ <input.txt command arg1 arg2
$ command <input.txt arg1 arg2
$ command arg1 <input.txt arg2
$ command arg1 arg2 <input.txt
$ cat input.txt | command arg1 arg2
pr -3tas,
-
pr
: プリンタ出力用整形コマンド -
-3
: 3段組みで -
-t
: ヘッダなしで -
-a
: 下方向ではなく横方向に (後述) -
-s,
: カンマ区切りで
-a
が無い場合、段組みの挙動となる
$ seq 9 | pr -3ts,
1,4,7
2,5,8
3,6,9
paste -d, - - -
paste
はファイルを行単位に結合する。
今回はファイルとして標準入力 (-
) を3回指定している。
paste
$ paste -d, a.txt b.txt c.txt
a1,b1,c1
a2,b2,c2
a3,b3,c3
a4,b4,c4
awk 'ORS=NR%3?",":"\n"'
awk の基本1 (基本形式)
$ awk '条件式{処理}' # 条件式 が 真 の場合 {処理} を実行する。
$ awk '{処理}' # 条件式 が暗黙的に 真 となる。
$ awk '条件式' # {処理} が暗黙的に {print $0} となる。<- 今回のパターン
awk の基本2 (代入演算子)
### 代入演算子 = は演算結果として代入後の結果を返す。
### 以下の () 内は最終的に a への代入結果の 4 に評価される。
$ awk 'BEGIN{print (a=2+2); print a}'
4
4
### 今回は ORS 変数への代入結果が "," or "\n" なので 条件式 は必ず 真 となる。
awk の基本3 (ORS)
### ORS 変数で print の改行記号が変更可能。
$ awk 'BEGIN{print 1; ORS="@"; print 2; ORS="/"; print 3}'
1
2@3/
- まとめ
- awk の基本形は
awk '条件式{処理}'
-
条件式
はORS=NR%3?",":"\n"
(=引数全体) -
{処理}
は{print $0}
(暗黙的に指定) -
ORS
変数への代入結果は","
か"\n"
なので条件式
は必ず真 -
ORS
変数を3行おきに"\n"
、それ以外の行は","
とし、print
の改行記号を調整している
- awk の基本形は
perl -pe'$.%3&&s/\n/,/'
-
-p
: 行ごとに暗黙的にprint($_)
を実行-
$_
: 入力行 (awk の$0
)
-
-
-e
: コマンドを指定 -
$.
: 現在の行番号 (awk のNR
) -
s/\n/,/
: s 演算子で置換- 暗黙的に
$_ =~ s/\n/,/
となり、$_
が置換される
- 暗黙的に
-
&&
で短絡評価され、$.%3
が真の場合に限りs/\n/,/
が実行される
split -l3 --filter=paste\ -sd,
split
### -l3: 3行ずつに分割
### --filter=command: 分割結果それぞれに対して command を実行
$ seq 6 | split -l3 --filter='cat -n'
1 1
2 2
3 3
1 4
2 5
3 6
paste
### -s なし: 行ごとに結合
$ paste -d, a.txt b.txt c.txt
a1,b1,c1
a2,b2,c2
a3,b3,c3
a4,b4,c4
### -s あり: ファイルごとに結合
$ paste -sd, a.txt b.txt c.txt
a1,a2,a3,a4
b1,b2,b3,b4
c1,c2,c3,c4
### 標準入力を1つのファイルとして読む
$ cat a.txt | paste -sd,
a1,a2,a3,a4
perl -l0pe '$_.=$.%3?",":"\n"'
-
-l0
:print()
の改行を無効化 -
-p
: 行ごとに暗黙的にprint($_)
を実行-
$_
: 入力行 (awk の$0
)
-
-
-e
: 実行するコマンドを指定 -
.=
: 文字列結合代入演算子 (python3 の+=
) -
$.
: 現在の行番号 (awk のNR
)