来週ようやく夏休み!のnagata (@handlename) です。
シェルコマンドを実行したいとき、どうしてますか?
emacsを使って開発する場合、 ターミナルとemacsを行ったり来たりすることはよくあると思います。
現在のディレクトリのパスがほしかったり(pwd)、 IPアドレスを調べたかったり(ifconfig)、 あるいは編集中のテキストを処理したかったり。
そんな場合、いちいちターミナルに移動して、 出力結果を確認(場合によってはコピー)して、 あらためてemacsに戻ってくるのは面倒です。
それ、emacsからできます!
往復するのが面倒ならば、すべてemacs上で完結させてしまえばいいのです。
shell-mode を使うという手もありますが、 今回はもっとお手軽な M-! (shell-command) と M-| (shell-command-on-region) を紹介します。
コマンドを実行してみる
では、さっそくemacs上でシェルコマンドを実行してみましょう。
コマンド単体を実行
単純にシェルコマンドを実行したい場合は、 M-! を使います。 M-! とするとミニバッファにキャレットが移動するので、 その状態でシェルコマンドを打てばOKです。
たとえば、カレンダーを表示したり(cal)、
PHPの設定を確認したり(php -i)。
出力がウィンドウの4分の1以下だっただった場合は、 ウィンドウの下部に新しいバッファ作られ、そこに表示されます。 このバッファはキー操作をすると消えます。
出力がそれ以上ある場合は Shell Command Output というバッファが作られ、 現在のウィンドウを分割して出力を表示します。 出力が短い場合でもこのバッファが表示されている場合はこちらに表示されます。
(実は出力の長さに関わらず、出力結果はこのバッファに表示されるのですが、 短い場合は最前面に出てくるという動作をするかわりに、 仮バッファが作られるようになっています)
ちなみに、 C-u M-! とすると、 現在キャレットがある部分に出力結果を挿入します 。
バッファの内容を入力として実行
バッファ内のテキストを入力として使いたい場合は M-| を使います。 選択中のリージョンが標準入力としてシェルコマンドに渡されます。
grepで必要な部分だけを抜き出したり、 cutで必要な列だけ取り出したりできるわけですね。
M-! とは違って、出力は長さにかかわらず Shell Command Output に表示されます。 いちいちターミナルからコピペせずとも即編集できるのがいいですね!
C-u M-| とすると、リージョンを出力結果で置き換えます。
こんなときに使ってます
- csvから指定の行だけを取り出す (cut)
- ファイルのリストをつくる (ls)
- がっつりアクセスログを集計してみたり (grep, cut, sort, uniq)
- 何となく単語数を数えてみたり (wc)
…ぱっとしないですね。「何となく」なんて言っちゃってますし。
emacsからコマンドを呼び出せるということはつまり、 自分で書いたシェルスクリプトを emacsに組み込むことができるということになります。
elispを書かなくてもemacsの機能を拡張(したように使うことが)できるわけです。
たとえば…
この記事、はじめは org-mode で書いてから、 org-export (C-c C-e) でHTMLに直してます。
HTML単体で表示する場合はそれで充分なのですが、 ブログの記事として載せるには自動でつけられる修飾がちょっとじゃまです。
elispで機能を追加するにも、まずはその勉強から始めないといけないし、 いちいち置換して整形するのは面倒だし…。 そういうときこそ shell-command-on-region の出番です!
普段使っていて一番慣れているPHPで、こんなスクリプトを書いてみました。
simpleorghtml
~/bin にでも置いて、 org-export したテキストを選択してから C-u M-| simpleorghtml とすれば、選択した部分が処理済みのテキストに置き換わります。 最後にヘッダとフッタ部分を取り除けば(ここも自動化したい…) そのままブログに載せられるテキストのできあがりです。
実行するときの注意点
コマンドが終了するまで待たされる
シェルコマンドを実行すると、そのコマンドが終了するまでemacsが固まってしまいます。 うっかりpingとかtail -fとかを実行するとひどい目に遭うわけです。
終了までに時間がかかる、あるいはモニタリングするようなコマンドを実行する場合は、 末尾に「&」をつけると Async Shell Command バッファに非同期で出力してくれます。 C-c C-c でSIGINTシグナルを送れるので、 プロセスを終了させる場合はこれを使いましょう。
追加入力も「&」で!
パスワードの入力が必要だったり、 yes/no の確認の入力が必要だったりするコマンドは、 そのまま実行すると入力する部分で止まってしまいます。 前項と同様に「&」をつければ このような対話的な入力もできるようになります。
カレントディレクトリ
現在開いているファイルのディレクトリになります。
おわり
単純にgrep -vなんかを呼び出すのも便利ですし、 シェルスクリプトを書けばより柔軟な処理が可能な shell-command 。 お試しあれー!