パイプで渡したパスにcdできない
ターミナル上で、コマンドで出力したパスに移動したいことがままあるのですが、パイプでcd
コマンドに渡してもうまくいきません。
$ echo ~ | cd
# なにも起こらない
$ echo ~ | xargs cd
# なにも起こらない
$ cd "$(echo ~)"
# これはOK
ところで、実行可能ファイル形式のシェルスクリプトでcd
しても、現在のシェルに反映されないという問題があります。
これは、ファイルからシェルスクリプトを実行した場合、サブシェルが起動しているためです。
これと同様の理由で、パイプでつないだ先の部分でcd
してもexec /bin/bash
しても、元々のシェルには反映されません。
$ pwd | cd ~
# なにも起こらない
$ echo $$
32187
# パイプの前のコマンドはなんでもいい
$ pwd | cd ~;exec /bin/bash
$ echo $$ # プロセスIDが変化していない
32187
パイプを使い、さらに現在のシェルにcd
を反映させるには、もはや新たにコマンドを実行するしかありません。
AppleScriptを使い無理やり実現
以下はiTerm2依存ですが、他のターミナルエミュレータでも同様のスクリプトは書けると思います。
(Build 3.1対応)
~/.bashrc
pcd () {
if [ ! -p /dev/stdin ]; then
if [ $# -ge 1 ]; then
cd "$1"
shift
if [ $# -ge 1 ]; then
echo "Too many arguments. After second arguments are not processed."
fi
else
echo "ERROR: No stdin or argument"
return 1
fi
else
osascript -e "tell application \"iTerm\" to tell current session of current tab of current window to write text \"cd $(cat -)\""
fi
}
(パイプからの)標準入力がなければ、引数を移動先ディレクトリとして普通にcd
します。標準入力がある場合、そこにcd
するコマンドをAppleScript経由で実行します。
どうせなら、渡された引数や標準入力がディレクトリパスか判断してdirname
したり、後ろにパイプがないか判断してエラーチェックもしたいですね。