🌊

ワンライナーでよく使うコマンドまとめ

2024/04/15に公開

こんにちは,なっふぃです.

私はワンライナーが大好きで可能な限りワンライナーで実行しようとするのですが,その中で便利だなと思っているコマンド群を紹介します.

想定しているシェルは Bash および Zsh です.
なお GNU/Linux(Ubuntu 22.04)で動作確認しているので,その他の OS は要確認です.

はじめに — 思想的な注意

基本的にワンライナーの実現方法は一通りではなく,複数存在します.

一方で,私自身としては

  • ワンライナーは「できるだけ単純な機能」の積み重ね(piping)で実現するべし

と考えています.「できるだけ単純」というのは記憶力による制限のことで,具体的には「覚えるオプションの数はできるだけ少なく」つまり「一つのコマンドには一つのことをさせる」方が経験的に楽です.

したがって,以下で紹介するコマンドもより便利なオプションはたくさんありますし,「このオプションを使えばもっと短く書ける」という意見は当然出てきます.

あくまで私の好みということでご寛恕ください.

grep

言わずと知れた,正規表現によるフィルタリングのコマンド.

主なオプション

-v デフォルトでは指定した文字列を含むものを表示し,-v オプションでは含まないものを表示する.
-n 行番号を表示.後述の sedtr と組み合わせれば区切りの : を別の文字列に変更できる.
-i 大文字・小文字を無視(ignore case)
-E, -F, -P 正規表現の種類.それぞれ ERE,完全一致(正規表現を使わない),PRE.デフォルトは BRE.

ERROR 行のみを表示・非表示

$ cat hoge.log | grep 'ERROR'
$ cat hoge.log | grep -v 'ERROR'

行番号 マッチ行 の形式で表示

$ cat hoge.log | grep -n 'ERROR' | sed 's/:/ /'

・空行を非表示

$ cat hoge.txt | grep -v '^$'

head/tail

最初の n 行を表示(head)または最後の n 行を表示(tail).

主なオプション

-n 最初・最後の n 行を表示.デフォルトは 10

$ cat hoge.log | tail -n100

sed

文字列置換などを行う.Stream editor の略.

主なオプション

-e スクリプトを指定.プラットフォームによっては,-e を使わずとも直接第一引数に渡せる.複数指定するときは -e SCRIPT を連ねる.
-E -e の ERE 版.

スクリプトについて

様々なコマンドがある(see man sed)が,基本は s で何とかなる.Vim など ex の流れを汲んだソフトウェアと同じように使える.

・同時置換

$ cat hoge.txt | sed -e 's/foo/bar/g' -e 's/baz//'

・逐次置換

$ cat hoge.txt | sed 's/fooo/bar/g' | sed 's/foo/baz/g'

tr

文字クラスの置換.sed に近いが,特定の操作では sed よりも楽.
引数には文字または文字クラスを渡す.

主なオプション

なし 第一引数を第二引数へ置換
-d 第一引数を削除
-C 文字クラスの補集合(complement)を取る

・カンマをスペースに置換

$ cat hoge.csv | tr ',' ' '

・アルファベットを削除

$ cat hoge.txt | tr -d '[:alpha:]'

・アルファベットのみを表示

$ cat hoge.txt | tr -dC '[:alpha:]'

awk

プログラミング言語 AWK を実行する.ワンライナーにおいては,n 番目のフィールド(カラム)を表示するために用いられることが多い.

主なオプション

-F フィールドの delimiter を指定.デフォルトはスペース.

簡単な syntax

ワンライナーの場合,awk への引数は主に次の書き方に従えばよい.

  1. シングルクォートで囲む
  2. { STM; STM; ...; STM } の形.つまり,
    • 波括弧 {} で囲む,
    • 一つまたは複数の文(STM)から成る,
    • 複数の文はセミコロンで区切る.
  3. ワンライナーで用いる文は次のいずれか.
    • OFS = "X" — 出力フィールドの delimiter を指定.デフォルトはスペース.
    • print X — 出力を行う.X には「一つの式」または「複数の式をカンマで区切ったもの」を渡す.式には「何番目のフィールドか」を表す変数 $1, $2, ... を用いることができる.シェルの引数と同じく,インデックスは 1 始まり.

・入力がスペース区切りで,3番目のフィールドを出力

$ docker images | awk '{print $3}'

・入力がスペース区切りで,2番目と3番目と4番目のフィールドをスペース区切りで出力

$ cat hoge.log | awk '{print $2,$3,$4}'

・入力がカンマ区切りで,2番目と3番目のフィールドをハイフン区切りで出力

$ cat hoge.csv | awk -F, '{OFS = "-"; print $2,$3}'

sort/uniq

名前の通り,ソートしたり(sort)連続した重複行を操作したり(uniq)する.

様々な使い方ができるため,ここでは紹介しきれない.詳しくは man やヘルプを参照.

・Unique words を表示

$ cat hoge.txt | tr ' ' '\n' | sort | uniq

cut

指定範囲以外を削除.

主なオプション

-b 表示する文字範囲(in bytes)を指定.

範囲は次の形式で指定する.0-indexed で,すべて半開区間 [N,M) の意味.

  • N — N バイト目を表示
  • N- — N バイト目以降を表示
  • -N — N バイト目までを表示
  • N-M — N バイト目から M バイト目までを表示

・行頭 3 バイトを表示

$ cat hoge.txt | cut -b -3

nl

行番号を表示.

主なオプション

-v 指定した行番号から始める.デフォルトは 1.

その他のオプションもあるが,基本的には sed 等の組み合わせで代用可能.

・マッチした行に,上から順番に番号を付ける(1 始まり)

$ grep 'ERROR' hoge.log | nl

・マッチした行に,上から順番に番号を付ける(0 始まり)

$ grep 'ERROR' hoge.log | nl -v0

ruby

プログラミング言語 Ruby を実行.

ワンライナー(シェル芸)に外部のプログラミング言語を持ち出すのは邪道という考え方もある(実際,上述の awk にも嫌悪感を示す人はいる)が,私個人の意見としては,「使えるものはすべて活用してよい」と思っている.
したがって Ruby も多用している.

なぜ Ruby かと言えば,スクリプト言語の中でも syntax に自由度が高く,特にスクリプトの文字数を減らしやすいためワンライナーに向いているから.

使い方

基本的には,puts または p で出力できることと,readlines で読んで each/map で回すということを覚えれば何とかなる.
putsp の違いには注意が必要(Rust の DisplayDebug みたいな関係).

each/map には Proc を渡すことになるが,ワンライナーの場合は Symbol#to_proc を活用しないと大変かもしれない.

・各行(数値)の総和を求める

$ cat hoge.dat | ruby -e 'p readlines.map(&:to_i).inject(&:+)'

・各行の文字数(前後の空白を除く)の総和を求める

$ cat hoge.txt | ruby -e 'p readlines.map { |l| l.strip.size }.inject(&:+)'

xargs

各行に対してコマンドを実行.

・Docker のイメージを削除

$ docker images | grep HOGE | awk '{print $3}' | xargs docker rmi

・ファイルを移動かつ名前変更

$ ls ./tmp | xargs -I{} mv tmp/{} new/renamed-{}

find

ファイルを検索する.ワンライナーのソースとして使う.

主なオプション

-name ファイル名(basename)がマッチしたものを表示.
-regex 正規表現で検索.
-type f なら regular file のみ,d ならディレクトリのみを表示.デフォルトはすべて表示.

他にも多くのオプションが存在するが,ワンライナー紹介の域を超えるため割愛.

なお -delete-exec などの ACTIONS は事故りやすいため,個人的には使わずに xargs 等で解決することがほとんど.

$ find /etc -regex '.*\.service' -type f | xargs -I{} cp {} /backup/systemd/

Discussion