Windowsユーザーのための WSL2で始める Linux環境構築術 28

コマンド1行で作業を劇的に効率化! 今日から使える「ワンライナー」集

第28回の今回は、Linuxの作業を効率化するための実例として、さまざまなコマンドを組みわせて1行で使う「ワンライナー」について解説します。

水野 源

6:30

はじめに

前回は、Linuxの標準入出力について改めて解説しました。パイプを使って複数のコマンドを連携させれば、より複雑な処理を自由に組み立てられることが理解できたのではないでしょうか。

とはいえ、コマンドの組み合わせは無限大です。理屈は分かっても「具体的に何をどう組み合わせたら便利なのか」は分からない人も多いでしょう。そこで今回は、今すぐ使える便利なコマンド例を紹介します。「こういうことができる」という参考になれば幸いです。

「ワンライナー」とは

1つのコマンドを入力して実行し、完了したら次のコマンドをまた入力し…というのが通常のシェルの動作ですが、パイプやループ、論理演算などを組み合わせれば、複数のコマンドを1行に詰め込むことも可能です。

$ grep ERROR access.log | sort | uniq -c | sort -nr

上記の例は「access.logというログファイルからERRORという文字が含まれる行を抽出し、エラーの種類ごとに数を集計して多い順に並べる」という処理をたった1行で行っています。こうした1行のコマンドだけで処理を完結させる書き方を「ワンライナー」と呼びます。

ワンライナーはプロンプト上に直接コマンドを入力するため、テキストエディタを開いてスクリプトを組む必要もなく非常に手軽で便利です。複雑な処理をその場でインスタントに組み立て、同時に使い捨てられるため、作業効率を飛躍的に向上できるのです。

今日から使えるワンライナーの例

日常のよくあるタスクを解決するための、実践的なワンライナーの例を紹介します。

条件に合ったファイルを一括削除する

まずはシンプルな例から見ていきましょう。findコマンドを使って、条件に合ったファイルをまとめて削除するとします。findコマンドは指定したパス以下にあるファイルやディレクトリを検索するコマンドですが、条件や見つかったファイルに対するアクションを指定できます。

以下は、検索対象はカレントディレクトリ以下(.)、検索対象はファイル(-type f)、最終更新日が30日以上前(-mtime +30)という条件でファイルを検索し、見つかった対象を削除(-delete)するコマンドです。古いバックアップファイルをまとめて削除する、といったときに使えます。

$ find . -type f -mtime +30 -delete

他にも、この例とは逆に「直近xx日以内」を指定する、期間を分単位で指定する、更新日ではなくアクセス日で検索する、といったことも可能です。

重複したファイルを検出する

もう1つ、findを使って重複ファイルを検出する例を紹介しましょう。

$ find . -type f -exec md5sum {} + | sort | uniq -w32 -d

先ほどの例では、-deleteオプションで見つかった対象を削除しました。今回は見つかった対象に任意のコマンドを実行する-execオプションを使用します。-execオプションはその後に実行したいコマンドを記述します。またその際に「{}」が対象のファイル名に置き換えられます。ここでは見つかったファイルのハッシュ値をmd5sumコマンドで計算しています。その後の「+」はコマンドの終端を意味するターミネーターです。

md5sumコマンドの出力結果はsortコマンドにパイプしています。ハッシュ値でソートしているわけです。そして続いてuniqコマンドにパイプしています。uniqはソート済みのファイルから重複した行を検出するコマンドです。デフォルトでは行全体を比較しますが、ここでは-w32オプションを使って先頭32文字、つまりMD5チェックサム分のみを比較しています。-dオプションは重複があった行のみを表示するオプションです。これで「同じハッシュ値を持つファイル」を検出できるというわけです。

このワンライナーを実行すると、重複したファイルのハッシュ値とファイル名のリストが得られます。さらにcutコマンドにパイプしてファイル名だけを取り出し、xargsコマンドにパイプしてrmコマンドで削除する、といった応用も可能です。

ファイルの拡張子を変更する

Bashではループを1行で書くこともできます。以下はシンプルなforループを使い、ファイルの拡張子を変更する例です。

$ for file in *.txt; do mv "$file" "${file%.txt}.md"; done

ここではカレントディレクトリにある、拡張子が「.txt」のファイルを対象にループを行っています。ループが回るごとに対象となるファイル名が順次、シェル変数「$file」に格納されます。ループの内部ではこの変数を使ってmvコマンドでリネームを行っています。

ここで特徴的なのは「${file%.txt}」という記述です。これはパラメータ展開と呼ばれる機能で「変数$fileの末尾から.txtという文字列を削除して展開する」という意味になります。展開結果の後に「.md」を付加しているため、これで「example.txt」というファイル名を「example.md」に変更できるというわけです。

forループを即興で書けるようになると、コマンドでの作業効率が一気に上がります。ぜひマスターしましょう。

ファイルを一括でリネームする

これは前述の拡張子変更の応用で、基本的な構造は同じです。

$ for file in *\ *; do mv "$file" "${file// /_}"; done

違うのは、対象のファイルを「*\ *」と指定している点です。これにより、ファイル名にスペースを含むファイルが対象になります。またパラメータ展開が「${file// /_}」になっています。これは変数内のスペースを_(アンダースコア)に置換するという意味です。つまり、これは「ファイル名に含まれるスペースをアンダースコアに置き換える」というワンライナーです。

ファイル名にスペースが含まれているとコマンドやスクリプトによっては誤動作の原因になるため、アンダースコアに置き換えるというのは一般的なワークアラウンドです。こうした作業もワンライナーを使えば、一発で行えるわけです。

ファイルを並列ダウンロードする

xargsコマンドは標準入力からスペースや改行で区切られた文字列を読み込み、それらの文字列を引数として別のコマンドを起動します。簡単に言えば、引数のリストを渡すことで引数が異なる同じコマンドを複数並列に起動できます。以下はxargsを使ってcurlコマンドを複数起動し、ファイルを並列ダウンロードする例です。

 xargs -P 8 -n 1 curl -O <<'EOF'
https://releases.ubuntu.com/24.04/ubuntu-24.04.4-desktop-amd64.iso
https://releases.ubuntu.com/24.04/ubuntu-24.04.4-live-server-amd64.iso
https://releases.ubuntu.com/22.04/ubuntu-22.04.5-desktop-amd64.iso
https://releases.ubuntu.com/22.04/ubuntu-22.04.5-live-server-amd64.iso
EOF

ダウンロードしたいファイルのURLを「<<'EOF'」から「EOF」の間に1行1URLで列挙します。この書き方は「ヒアドキュメント」と呼ばれ、標準入力に渡す内容をインラインで記述できる便利機能です。ここではバージョンの異なるUbuntuのインストールメディア、4種類のURLを渡しています。xargsはこの4行を受け取り、curlコマンドを4並列で実行します。

標準入力はファイルや別のコマンドからだけでなく、このように手動で流し込むこともできるのです。一時ファイルを作らなくてよいため、使い捨ての処理を書く際に便利です。

肥大化しているディレクトリを探す

ディスクの空き容量が少なくなったときは、余計なファイルを掃除して空き容量を確保するのが鉄則です。どのディレクトリがどのくらいの容量を使っているかを把握するのに便利なのがduコマンドです。duは引数に指定したファイルやディレクトリが、どのくらいの容量を消費しているかを表示します。

$ du -hs * | sort -rh | head

ここでは、duに2つのオプションを付けています。1つは-sオプションで、これは引数に指定された項目ごとの合計サイズを表示します。引数にディレクトリを指定した場合、そのディレクトリが含むすべてのサブディレクトリとファイルの合計サイズを表示できるわけです。

もう1つが-hオプションで、これは人間にとって見やすく表示するためのものです。引数には「*(アスタリスク)」を指定し、カレントディレクトリの全ディレクトリとファイルを対象としました。

その結果をsortコマンドにパイプしてソートします。「-r」オプションを指定しているため、ソートした項目が降順、つまりサイズが大きい順に並びます。最後にこれをheadコマンドにパイプしています。headは標準入力から渡された内容の先頭10行だけを表示するコマンドで、ディスク容量を消費しているワースト10のディレクトリを表示できます。

Yes/Noプロンプトを作る

aptコマンドでパッケージをインストールしようとすると、本当に実行してよいか、Yes/Noを入力する確認プロンプトが表示されます。こうした確認プロンプトを自前で実装できるのが以下のワンライナーです。シェルスクリプトの内部などで、本当に実行してよいかの確認を促す場合に利用してみてください。

$ read -p "Continue? [y/N]: " yn && [[ $yn == y ]] && echo 'Run!'

readコマンドは標準入力から入力を読み取り、その結果を変数に格納するコマンドです。ここではキーボードからの入力を変数「yn」に格納しています。続いて「[[ ]](二重ブラケット)」が登場しました。これはBashの条件判定です。シェル変数$yn、つまり押されたキーが「y」かどうかを判定しています。もしyキーが押されていた場合は最後のechoコマンドが実行されます。実際はこのechoコマンド部分を任意のコマンドに置き換えてみてください。これで、あるコマンドを実行してよいかの確認プロンプトが作れます。

この例では、コマンド同士を繋ぐのにパイプではなく「&&」が使われています。これはANDを表す論理演算で、左辺が真だった場合に右辺の評価を行います。2つのコマンドを&&で繋ぐと「左辺(最初に実行するコマンド)が成功した場合に、右辺(後続のコマンド)を実行する」という意味になります。

例えば、以下はexampleというディレクトリを作成し、作成に成功したらcdコマンドで移動する例です。こうしたコマンドの書き方はシェルの定石なので、この機会に覚えておきましょう。

$ mkdir example && cd example

ちなみに、2つのコマンドを「||」で繋ぐと「左辺のコマンドが失敗した場合に後続のコマンドを実行する」という意味になります。こちらはエラー時の後処理などによく利用されています。例えば、以下はあるコマンドが失敗した場合にexitでシェルを終了する例です。スクリプト内のエラーハンドリングで、よくこうした書き方をします。これもセットで覚えておくと良いでしょう。

$ 何らかのコマンド || exit 1

WSLで使えるワンライナーの例

WSL環境ではWindows側のコマンドを直接叩くなど、通常のLinux環境よりも多くのことができます。こうしたWSLならではのワンライナーも紹介しましょう。

エクスプローラで今のディレクトリを開く

WSLでは、Windowsにインストールされているexeファイルをシェルから起動できます。例えば、explorer.exeの引数にカレントディレクトリを指定すれば、エクスプローラでそのディレクトリを開けます。

$ explorer.exe .

WSLで作業中にGUIのファイルマネージャーを操作したくなることもあるでしょう。何度もフォルダをダブルクリックしてWSLの深いディレクトリ階層を辿るのは面倒ですが、このコマンドであれば目当てのディレクトリを一発で開けて便利です。

WindowsとWSLのパスを相互変換

WindowsのエクスプローラからWSL内のファイルを操作できます。また、WSL内からもCドライブ上にあるWindowsのファイルを操作できます。このようにWindows/Linuxという異なる環境でありながら、シームレスに相互のファイルを操作できるのがWSLのメリットの1つです。

しかしWindowsとLinuxではファイルのパス表記が異なります。またWSL2はHyper-Vで動いている仮想マシンなのでファイルはディスクイメージ内に保存されており、Cドライブ以下のツリー上にあるわけではありません。9pのネットワーク共有を経由してアクセスする必要があり、UNCパスを指定しなければなりません。

そこでWindowsとWSLのパスを相互変換するコマンドがwslpathです。引数にWindowsのパスを指定すると、WSL上からアクセスできるパスに変換します。以下はWindowsユーザーのホームフォルダである「C:\Users\mizuno」を指定した例です。「/mnt/c/Users/mizuno」という変換結果が表示されました。WSL上からはこのパスでWindowsのホームフォルダにアクセスできるというわけです。

$ wslpath "C:\Users\mizuno"
/mnt/c/Users/mizuno

また-wオプションとWSLのパスを指定すると、Windows上からアクセスできるUNCパスに変換してくれます。以下はWSL内のホームディレクトリ「/home/mizuno」を指定した例です。UNCパスである「\\wsl.localhost\Ubuntu-24.04\home\mizuno」という変換結果が表示されました。Windowsのエクスプローラのアドレスバーにこのパスを入力すると、エクスプローラからWSL内のホームディレクトリを閲覧できます。

$ wslpath -w /home/mizuno
\\wsl.localhost\Ubuntu-24.04\home\mizuno

WSLからWindowsの既定アプリで開く

Windowsにはstartというコマンドがあります。これはmacOSでいうopenコマンドに相当するもので、Windowsの関連付けに従ってアプリを起動できます。以下はWSL上にあるテキストファイルを開く例です。

$ cmd.exe /c start $(wslpath -w ./example.txt)

WSLからWindowsのcmd.exe(コマンドプロンプト)を呼び出しています。cmd.exeの/cオプションはその後に続くコマンドを実行し、コマンドプロンプトを終了するためのものです。そして実行するstartコマンドの引数として、カレントディレクトリにあるexample.txtのパスを渡しています。この際、内部的に前述のwslpathを呼び出し、WSL上のファイルパスをWindows上からアクセスできるパスに変換しています。

つまりこのコマンドを実行すると、Windows上から見えるexample.txtを引数としてstartコマンドが実行されます。拡張子が.txtのファイルなので(デフォルトでは)メモ帳が起動し、このファイルが編集可能な状態になります。

WSL上のファイルをWindowsのアプリに渡したいときに便利なワンライナーです。

WSLからクリップボードにコピーする

WSLのターミナルに表示された結果をWindowsから利用したいことはよくあります。例えば、コマンドの出力をWindowsのテキストエディタにコピペしたいような場合です。Windowsターミナル上の出力をドラッグして選択した上で右クリックすればコピーできるのはご存知の通りですが、実はクリップボードへのコピーを行うコマンドが存在します。それがclip.exeです。

$ echo "hello" | clip.exe

clip.exeは標準入力から渡された内容をクリップボードにコピーします。上記の例では「hello」という文字列がクリップボードにコピーされます。プラットフォームをまたいだクリップボードの共有が可能になるというわけです。いちいち手でコピーせずともコマンドの出力を直接Windowsに渡せるため、ドキュメントの作成などに威力を発揮するでしょう。

ただし、WSL上で出力した日本語をコピーしてWindows上にペーストすると文字化けしてしまいます。これはWSLがUTF-8で日本語を扱うのに対し、WindowsではShift-JISを期待しているために起こる現象です。そのような場合はclip.exeに渡す前にnkfなどをパイプで挟み、文字コードを変換すると良いでしょう。なお、nkfコマンドはnkfパッケージでインストールできます。

$ echo "ハロー" | nkf --sjis | clip.exe

クリップボードの内容をWSLで整形する

clip.exeはクリップボードへコピーするためのコマンドで、ペーストはできません。クリップボードの中身を読み出すにはPowerShellの「Get-Clipboard」コマンドレットを使います。これでクリップボードの中身を、WSLの標準出力へ読み出せます。

$ echo "hello" | clip.exe
$ powershell.exe -command "Get-Clipboard" | tr '[:lower:]' '[:upper:]'
HELLO

標準出力に読み出せるので、あとはパイプを繋けば自由に編集が可能です。上記はまずclip.exeでクリップボードに「hello」という文字列をコピーした上でPowerShellを使ってそれを取り出し、trコマンドにパイプしてアルファベット小文字を大文字に変換しています。

Windowsのアプリ(Webブラウザなど)でコピーした文字列をWSL上で加工して利用したいような場合に便利です。ここからさらにclip.exeにパイプすれば、クリップボードの中身を変換するワンライナーも作れます。

おわりに

本来の使い方だけでなく「思ってもみなかったような使い方」すらできてしまうのが、Linuxコマンドの特徴です。第6回で解説した基礎コマンド群や、第18回で解説した現代的なコマンド群などを改めて眺めてみましょう。「あれとあれを組み合わせれば、こんな便利なことができるかも?」と考えられるようになれば、中級者への第一歩です。

今回はコマンドを使いこなす実例として、便利なワンライナーをいくつか紹介しました。しかし、これらはあくまで「こういうこともできる」という1例にすぎません。コマンドの組み合わせは自由自在です。ぜひ自分だけの便利なコマンドの活用例を考えてみてください。

この記事のキーワード

この記事をシェアしてください

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored