Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2912

ファイルの先頭 N 行と末尾 M 行を取り出すワンライナー

$
0
0
tee を使う方法 $ seq 100000 | nl -s: | tee -p >(head -n 10) >(tail -n 3) > /dev/null | sort -un | cut -d: -f2- 1 2 3 4 5 6 7 8 9 10 99998 99999 100000 処理の流れ 最初に nl -s: で行番号を付けます。次に tee -p >(head -n 10) >(tail -n 3) > /dev/null で先頭の 10 行と末尾の 3 行を取り出します。 取り出そうとする行数が入力テキストの行数より大きい場合は重複行が発生します。また、結果行の順序は保証されないため、sort -nu でソートし、重複行を削除します。 ここまでの処理で、以下の状態となります。 $ seq 100000 | nl -s: | tee -p >(head -n 10) >(tail -n 3) > /dev/null | sort -un 1:1 2:2 3:3 4:4 5:5 6:6 7:7 8:8 9:9 10:10 99998:99998 99999:99999 100000:100000 最後に cut -d: -f2- で行番号を削除することで、期待する結果を得ることができます。 上手くいかなかった方法 最初、以下のように書いたところ、期待する結果は得られず、しかも実行するたびに異なる出力が行われてしまいました。 冒頭に出したコマンドとの違いは、tee に -p オプションを指定しているかどうかだけです。これについて、コメント欄で @angel_p_57 さんに重要なポイントを教えていただきました。(次の項目へ) $ seq 100000 | nl -s: | tee >(head -n 10) >(tail -n 3) > /dev/null | sort -un | cut -d: -f2- 1 2 3 4 5 6 7 8 9 10 5893 5894 5895 プロセス置換と tee の -p オプション tee >(head -n 10) >(tail -n 3) のように >(COMMAND) と書くと、bash のプロセス置換 (process substitution) になります。 プロセス置換は元のコマンドパイプラインとは非同期で実行されます。また、tee はパイプへの書き込みエラーが発生した場合、デフォルトでは直ちに終了します。tee の -p や --output-error=MODE オプションを指定することで、この動作を変更できます1。 今回は -p (--output-error=warn-nopipe と同じ) を指定することで、発生した問題を解決できました。 pee を使う方法 $ seq 100000 | nl -s: | pee 'head -n 10' 'tail -n 3' | sort -nu | cut -d: -f2- 1 2 3 4 5 6 7 8 9 10 99998 99999 100000 moreutils に含まれる pee を利用する方法です。コメント欄で @yoichi22 さんに教えていただきました1。 pee は tee とは違い、標準入力の内容を標準出力に出力しません。パイプで使うことに特化した tee という感じのコマンドです。 処理の流れ 基本的な考え方は tee を使う方法と同じです。 没案 試行錯誤して作ったものの、フィードバックを受けて、より良い方法が分かった今となっては微妙な方法です。 $ seq 100000 | nl -s: | tee >(sed '11,$d') >(tac | sed '4,$d' | tac) > /dev/null | sort -nu | cut -d: -f2- 1 2 3 4 5 6 7 8 9 10 99998 99999 100000 別解 入力データがファイルの場合は、次のように書くこともできます。 $ cat a.txt | head -n 10 && cat a.txt | tail -n 3 1 2 3 4 5 6 7 8 9 10 99998 99999 100000 次のコメントを参照: #comment-38a252900c08a1132973 ↩

Viewing all articles
Browse latest Browse all 2912

Trending Articles