ソートしますが、ヘッダー行を上部に保持します


56

私は、まず列ヘッダーの束である1行を作成し、次にデータの束であるプログラムから出力を取得しています。この出力のさまざまな列を切り取り、さまざまな列に従ってソートして表示したいと思います。ヘッダーを使用しない-k場合、列のサブセットsortと一緒に表示しcutたりawk、列のサブセットを表示したりするオプションを使用して、簡単に切り取りと並べ替えを実行できます。ただし、このソート方法では、列ヘッダーと残りの出力行が混在します。ヘッダーを一番上に保つ簡単な方法はありますか?


1
私は次のリンクに出くわしました。ただし、この手法を使用{ head -1; sort; }することはできません。常に最初の行の後のテキストの束を削除します。なぜこれが起こるのか誰にも分かりますか?
ジョンデリー

1
headバッファに複数の行を読み込んで、そのほとんどを捨てているためだと思います。私のsedアイデアにも同じ問題がありました。
アンディ

@jonderry-この手法は有効lseekな入力でのみ機能するため、パイプから読み取るときには機能しません。あなたは、ファイルにリダイレクトする場合、それは動作します>outfileし、次に実行します{ head -n 1; sort; } <outfile
don_crissti

回答:


58

Andyのアイデアを盗み、それを機能にして、使いやすくする:

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

今私ができること:

$ ps -o pid,comm | body sort -k2
  PID COMMAND
24759 bash
31276 bash
31032 less
31177 less
31020 man
31167 man
...

$ ps -o pid,comm | body grep less
  PID COMMAND
31032 less
31177 less

ps -C COMMANDは、よりも適切かもしれませんgrep COMMANDが、それは単なる例です。また、-Cなどの別の選択オプションも使用した場合は使用できません-U
ミケル

または多分それは呼ばれるべきbodyですか?同様にbody sortまたはbody grep。考え?
ミケル

3
からheaderに名前を変更しbodyました。これは、本文に対してアクションを実行しているためです。うまくいけばもっと理にかなっています。
ミケル

2
body後続のすべてのパイプライン参加者を呼び出すことを忘れないでください:ps -o pid,comm | body grep less | body sort -k1nr
ビショップ

1
あなただけ書くことができ@Tim <foo body sort -k2body sort -k2 <foo。必要なものから1つだけ余分な文字。
ミケル

37

bashを使用すると、ヘッダーを次のように上部に保持できます。

command | (read -r; printf "%s\n" "$REPLY"; sort)

または、perlで実行します。

command | perl -e 'print scalar (<>); print sort { ... } <>'

2
+1すごい。シェル関数としてまとめる価値があると思います。
ミケル

1
1、サブシェルが好ましく、または、なぜ何らかの理由で{}OKの代わりに()
ジョンデリー

2
IFS=入力を読み取るときに単語分割を無効にします。を読むときに必要だとは思わない$REPLY。が設定されているecho場合xpg_echo(デフォルトではない)、バックスラッシュエスケープを展開します。printfその場合はより安全です。echo $REPLY引用符がないと、空白が凝縮されます。echo "$REPLY"大丈夫だと思う。read -r入力にバックスラッシュエスケープが含まれる場合に必要です。この一部は、bashのバージョンに依存する場合があります。
アンディ

1
@Andy:うわー、あなたは正しい、read REPLY; echo $REPLY(先頭のスペースを削除する)とread; echo $REPLY(しない)の異なるルール。
ミケル

1
@Andy:IIRC、のデフォルト値はxpg_echoシステムに依存します。たとえば、Solarisではデフォルトでtrueになっていると思います。これが、Gillesがprintf非常に好きな理由です。予測可能な動作を持つのはそれだけです。
ミケル

23

スクリプトでうまく機能する素敵なawkバージョンを見つけまし

awk 'NR == 1; NR > 1 {print $0 | "sort -n"}'

1
私はこれが好きですが、少し説明が必要です-パイプはawkスクリプトの中にあります。それはどのように機能しますか?sortコマンドを外部から呼び出していますか?awk内でのパイプの使用を説明するページへのリンクを少なくとも知っている人はいますか?
ワイルドカード

@Wildcardの公式マニュアルページまたはこの入門書を確認できます。
-lapo

4

ハックが効果的:並べ替える前に0、すべてのヘッダー行と1他のすべての行に追加します。ソート後に最初の文字を取り除きます。

… |
awk '{print (NR <= 2 ? "0 " : "1 ") $0}' |
sort -k 1 -k… |
cut -b 3-

3

出力をパイプ処理してすべてを並べ替えることができますが、最初の行を一番上に保つことができる魔法のperl行ノイズがあります: perl -e 'print scalar <>, sort <>;'


2

私はcommand | {head -1; sort; }解決策を試しましたが、それが本当に物事を台無しにすることを確認することができます - headパイプから複数の行を読み取り、最初の行だけを出力します。したがって、読み取られhead なかっsortた残りの出力は、2行目以降の残りの出力ではなく、に渡されます!

その結果、コマンド出力の先頭にあった行(および1行の部分!)が失われます(ただし、最初の行がまだあることを除いて)- wc最後にパイプを追加することで簡単に確認できます上記のパイプライン-しかし、これを知らない場合、トレースするのは非常に困難です!それを解決する前に、出力に部分的な行(最初の100バイト程度の切り捨て)があった理由を解明するために、少なくとも20分を費やしました。

きれいに機能し、コマンドを2回実行する必要がなかったのは、次のとおりです。

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile
sed 1d $myfile | sort

rm $myfile

出力をファイルに入れる必要がある場合、これを次のように変更できます。

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile > outputfile
sed 1d $myfile | sort >> outputfile

rm $myfile

それを回避するために、一度に1バイトずつ入力を読み取るksh93のheadビルトインまたはlineユーティリティ(まだ1 つあるシステムで)またはgnu-sed -u qまたはを使用できますIFS=read -r line; printf '%s\n' "$line"
ステファンシャゼル

1

これが一番簡単だと思います。

ps -ef | ( head -n 1 ; sort )

またはこれはサブシェルを作成しないため、おそらくより高速です

ps -ef | { head -n 1 ; sort ; }

その他のクールな用途

ヘッダー行の後の行をシャッフルします

cat file.txt |  ( head -n 1 ; shuf )

ヘッダー行の後の逆行

cat file.txt |  ( head -n 1 ; tac )

2
unix.stackexchange.com/questions/11856/…を参照してください。これは実際には良い解決策ではありません。
ワイルドカード

1
動作していない、cat file | { head -n 1 ; sort ; } > file2頭だけを表示
ピータークラウス

0
command | head -1; command | tail -n +2 | sort

4
これはcommand2回開始されます。したがって、特定のコマンドに限定されます。ただし、psこの例の要求されたコマンドでは機能します。
ジョフェル

0

シンプルでわかりやすい!

<command> | head -n 1; <command> | sed 1d | sort <....>
  • sed nd ---> 'n'は行番号を指定し、 'd'は削除を表します。

1
1年半前にjofelがSarvaの答えについてコメントしたように、これはcommand2回始まります。そのため、パイプラインでの使用にはあまり適していません。
ワイルドカード

0

コマンドの解決策を探してここに来ましたw。このコマンドは、誰がログインしていて何をしているのかの詳細を表示します。

結果を並べ替えて表示するために、ヘッダーを上部に保持したままにします(ヘッダーは2行あります)。

w | head -n 2; w | tail -n +3 | sort

明らかにこれはコマンドをw2回実行するため、すべての状況に適しているとは限りません。ただし、その利点から、覚えるのはかなり簡単です。

tail -n +3「3番目以降のすべての行を表示する」という意味であることに注意してください(詳細man tailは参照)。


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