ターミナルからググろう(ターミナルから検索キーワードをブラウザに送る)

ターミナルから検索クエリをブラウザに送れるようにしてみました。

先日、シェルを bash から zsh に変えたので環境を見直してるところです。

ターミナルで作業中にネットで調べごとをするのに「ブラウザに切り替えて〜、コマンドL押して〜、検索ワード入れて〜。あれ?そもそもブラウザどこだよ???」なんてことがよくあります。Automator とかでサービスを作ってショートカットキーで呼び出すこともできそうですが、「ターミナル使ってるならターミナルで呼び出しちゃえばいいじゃない!」ってことで。


.zshrc とか .bashrc に関数を書きます。

.zshrc
# --------------------------------------
# Google search from terminal
# --------------------------------------
google(){
    if [ $(echo $1 | egrep "^-[cfs]$") ]; then
        local opt="$1"
        shift
    fi
    local url="https://www.google.co.jp/search?q=${*// /+}"
    local app="/Applications"
    local c="${app}/Google Chrome.app"
    local f="${app}/Firefox.app"
    local s="${app}/Safari.app"
    case ${opt} in
        "-c")   open "${url}" -a "$c";;
        "-f")   open "${url}" -a "$f";;
        "-s")   open "${url}" -a "$s";;
        *)      open "${url}";;
    esac
}


使い方は簡単。

google -f 2ch まとめ


以上。


というのはあまりにも雑なのでもう少し細かく説明すると…

  1. google というコマンドで上の関数が呼び出される。
  2. オプションでブラウザの指定ができる。(上の例では Firefox で開く)
  3. 残りの引数は全部検索クエリとして渡される。(上の例では "2ch" と "まとめ")


という内容です。オプションでブラウザの指定がなければデフォルトのブラウザが使われます。シェルの言語設定によるかもしれませんが、日本語も検索もOKです。

関数名は「google」じゃなくて「ggr」とか「ggrks」でもアリ。


欠点

ダブルクオートを使うときはシングルクオートで囲むかバックスラッシュでエスケープしなくてはいけない。(キーワードの先頭に「-」が付くと否定条件になるため)

google find "-type"   # NG(typeが否定条件になる)
google 'find "-type"' # OK
google find \"-type\" # OK


コードの詳細

まず、オプションがあるかどうかチェックします。書き方が楽なんで egrep 使ってますが $1 がオプションだと判断できればなんでもいいです。^-[cfs]$ では -c-f-s がマッチします。これは使うブラウザ次第。条件にマッチしたら $1 を変数 ${opt} に入れて shift して、残りの引数を検索キーワードだけにしておきます。

if [ $(echo $1 | egrep "^-[cfs]$") ]; then
    local opt="$1"
    shift
fi


次に、残りの引数を Google の検索パラメータに渡します。このとき、変数内文字列置換で半角スペースが「+」に変換されるようにしています(「%20」でもいいかも)。

local url="https://www.google.co.jp/search?q=${*// /+}"


ブラウザを変数に登録していきます。とりあえず -c で Google Chrome、-f で Firefox、-s で Safari です。

local app="/Applications"
local c="${app}/Google Chrome.app"
local f="${app}/Firefox.app"
local s="${app}/Safari.app"


case 文でコマンドを分けます。open コマンドは引数が URL の場合、アプリケーションを選択しなければデフォルトのブラウザで開かれます。

case ${opt} in
    "-c")   open "${url}" -a "$c";;
    "-f")   open "${url}" -a "$f";;
    "-s")   open "${url}" -a "$s";;
    *)      open "${url}";;
esac


いきなり case 文で正規表現を使って分岐していないのは URL を変数に登録しておきたかったから。(そうしないと case を2回使わなきゃいけない…気がした)

デフォルトブラウザでしか開かないならこれでいいかな。

google(){
    open "https://www.google.co.jp/search?q=${*// /+}"
}


まだ縮められそうだけどとりあえず今日はこの辺で。


追記1

変数と case を分けているのが無駄だったので少しまとめてみた。文字列置換と位置パラメータ指定切り出しが同時にできれば shift しなくてもいいんだけどなぁ。わざわざ半角スペース変換しなくても最近のブラウザはちゃんと処理してくれるからそれ省けばいいんだけど。 ←変数作って上書きしていくか、諦めて sed 使え。

sh
google(){
    local a="/Applications"
    local u="https://www.google.co.jp/search?q="
    case $1 in
        -c) shift; open "${u}${*// /+}" -a "${a}/Google Chrome.app";;
        -f) shift; open "${u}${*// /+}" -a "${a}/Firefox.app";;
        -s) shift; open "${u}${*// /+}" -a "${a}/Safari.app";;
         *) open "${u}${*// /+}";;
    esac
}

追記2

ようやく納得いくものができました。

結局、bash と zsh で ${name#pattern} の動作が違う *2 ので sed コマンドを使用。先頭のハイフンから始まるアルファベット1文字とスペース1個を取り除き、残りのスペースを[+]に置換。これでオプションフラグを判別して shift する必要がなくなった。それから、検索 URL を Google のウェブページで検索したものに修正。位置情報っぽいものとか画面サイズ的なものは除外。

open コマンドでアプリケーションを指定する場合、[-a]オプションを追加しなきゃいけないけど case 文の中に毎回書くのは不便なので ${name:+word} を使って変数 _gA があるときだけ[-a]を出力させる。

実行コマンドを画面に出力したかったのでシングルクオートで書いて eval で実行。[$_]みたいな感じで最後の引数だけじゃなくて前のコマンドを全部拾える方法って無いんだろうか?そのうち表示する必要もなくなりそうだからとりあえずいいや。

最後に unset コマンドで変数を削除。bash だと ${!prefix*} があるんだけど、これは zsh では使えないっぽい。仕方ないのでブレース展開で一括指定。


Trackback