私は多数の列を並べ替えるためのパイプライン可能な限り行のコードを探しています(たとえば、awk
このようなコマンドで列番号を手動で入力することはawk '{print $3,$2,$1}'
不可能です)。順序は、ソート方式(文字、数字 - 「ソート」と似ていますが、行ではなく列に対応します)を使用するか、テキストファイルで任意に指定できます。
答え1
Perlを使ったシンプルなソリューション。
値の配列を埋めることから始めます。
➜ ~ x="$(cat << END
22 79 83 16 25 1 4 82 34 68
48 43 2 26 39 2 71 43 57 41
77 70 73 18 76 33 21 54 67 50
6 65 46 92 25 70 53 28 3 40
32 60 76 39 26 44 34 91 24 39
59 75 96 85 52 98 69 28 72 94
48 0 88 55 6 78 1 54 83 81
3 43 48 24 23 87 28 98 38 67
97 73 74 24 92 67 1 27 90 85
32 55 52 44 26 37 87 37 100 92
END
)"
➜ ~ perl -lane '@i=sort({ @F[$a] <=> @F[$b] } 0..$#F) if $.==1;
print join("\t", @F[@i])' <<< "$x"
1 4 16 22 25 34 68 79 82 83
2 71 26 48 39 57 41 43 43 2
33 21 18 77 76 67 50 70 54 73
70 53 92 6 25 3 40 65 28 46
44 34 39 32 26 24 39 60 91 76
98 69 85 59 52 72 94 75 28 96
78 1 55 48 6 83 81 0 54 88
87 28 24 3 23 38 67 43 98 48
67 1 24 97 92 90 85 73 27 74
37 87 44 32 26 100 92 55 37 52
-a
@F
: 配列の自動分割と自動塗りつぶしの有効化-n
:while ループの各行を読み込みます。$#F
: 配列内の最大のゼロベースのインデックスを返します。<=>
:ソート機能の比較演算子(数値入力のみ可能、文字列比較に使用cmp
)sort
:配列内のソートされたインデックスを返します0..$#F
(組み込み$a
合計$b
変数を使用)。@i
@F
:(この場合)を含むソートされた@i = 5 6 3 0 4 8 9 1 7 2
インデックス配列$. == 1
:最初の行でのみ実行されます。@F[@i]
:ソートされたインデックスに従って各行をソートします。
源泉:https://learnbyexample.gitbooks.io/command-line-text-processing/content/perl_the_swiss_knife.html
答え2
これはストリーミング可能なソリューションです。
列の最初の行に基づいてソートし、そうでなければ他の場所でソートキーを取得するように調整するとします。
ソートキーの生成(Rushの配列の再利用):
echo -e "b a c\n5 4 6\n8 7 9" > data
key=$(head -n1 data | sed 's/ \+/\n/g' | nl -n ln | sort -k2 | cut -f1)
$key
現在確立されている:
2
1
3
次に、キーを使用して列をソートします。
awk -v key="$key" '
BEGIN { split(key, order, "\n") }
{
for(i=1; i<=length(order); i++) {
printf("%s ", $order[i])
}
printf("\n");
}' data
出力:
a b c
4 5 6
7 8 9
答え3
これが最善の解決策であるか、巨大なテーブルで素早く実行されるかはわかりませんが、うまくいきます。
echo -e "2 1 3\n5 4 6\n8 7 9" | \
awk '{for (i=1;i<=NF;i++) {a[NR,i]=$i} } \
NF>p {p=NF} \
END {for (j=1;j<=p;j++) {str=a[1,j]; \
for (i=2;i<=NR;i++) {str=str" "a[i,j];}print str}}' \
| sort -n | \
awk '{for (i=1;i<=NF;i++) {a[NR,i]=$i} } \
NF>p {p=NF} \
END {for (j=1;j<=p;j++) {str=a[1,j]; \
for (i=2;i<=NR;i++) {str=str" "a[i,j];}print str}}'
仕組み:テーブルを転置してから、テーブルを並べ替えて再配置します。
ところでecho -e "2 1 3\n5 4 6\n8 7 9"
結果は
2 1 3
5 4 6
8 7 9
スクリプトが機能した後、結果は次のようになります。
1 2 3
4 5 6
7 8 9
PS私はawkで配列をソートすることが可能だと思いましたが、残念ながらそうするのに十分な時間がありませんでした。
答え4
ファイルがスペースで区切られたxy.datであるとします。
cat xy.dat | while read line ; do
echo $line | tr ' ' '\n' | sort -nr | tr '\n' ' '
echo
done
私のテストデータは数値的に昇順だったので、精神的にsort -nrを使って降順にし、どの程度効果を見ました。
設定可能にするには、ソートフラグを引数として渡すと、昇順(なし)と降順 -r(逆順)だけでなく、-n(数値)なども許可されます(参照:)sort --help
。設定したいもう1つは区切り文字です。スペース/タブ/セミコロン/カンマ?たぶん、正規表現グループは"[ \t]"
スペースやタブを表現するのが好きですか?では、出力は何に使用されますか?ファイル名をハードコードしたくありませんが、プログラムをフィルタとして使用してください。簡単な方法は次のとおりです。
#!/bin/bash
flags=$1
delim=$2
while read line ; do
echo $line | tr "$delim" '\n' | sort $flags | tr '\n' "$delim"
echo
done
移動する:
cat num.dat | bash colsort.sh "-nr" ' '
4 3 2 1
8 7 6 5
11 10 9
cat num.dat | bash colsort.sh "-r" ' '
4 3 2 1
8 7 6 5
9 11 10
cat num.dat | bash colsort.sh "--" ' '
1 2 3 4
5 6 7 8
10 11 9
--(アルファベット順:10 11 9)、逆順(9 10 11)、数字(11 10 9)など、デフォルトで並べ替えられている方法を確認してください。
主にスペース、タブなどをマスクする方法を文書化すると便利です。