Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2863

[bash] カレントディレクトリが存在しなくてもcd ./は成功する

$
0
0

環境

$ bash --version
bash --version
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)

事象

$ mkdir test; cd test;
$ rmdir ../test <- カレントディレクトリを削除
$ cd ./
cd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
$ echo $?; pwd
0            <- エラーメッセージが出力されるが成功している
/home/user42/test/./  <- pwdがおかしくなっている
$ cd ././/////./././/////././././///
cd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
$ echo $?; pwd
0
/home/user42/test/./././/////./././/////././././/// <- !?!?!?
$ cd ../
$ echo $?; pwd
0
/home/user42 <- cd ../すると元に戻る

理由

bashは入力されたパスへの移動に失敗すると、入力値を直接引数としてcdに再挑戦するから。

調査

bashのソースは公式サイトからダウンロードできるので、読んでみました。
builtins/cd.defの中でcdの動作が定義されています。

実際にchdir(カレントディレクトリを変更する関数)を呼び出しているchange_to_directoryの処理をのぞいてみると、このようなコメントがあり、上記の動作が起こる理由が説明されています。

/* We're not in physical mode (nolinks == 0), but we failed to change to
     the canonicalized directory name (TDIR).  Try what the user passed
     verbatim. If we succeed, reinitialize the_current_working_directory.
     POSIX requires that we just fail here, so we do in posix mode. */

POSIXモード1でない際、正規化2したパス(TDIR)3へのcdが失敗すると、引数をそのままcdで試し、成功した場合、the_current_working_directory4の再設定を行うと記述されています。

cd ./を実行するとchdir("pwdの出力 + ./")に失敗した後、chdir("./")に挑戦しているようです。

bashcdが一度失敗しても引数そのままのcdに挑戦してくれる親切設計なんですね。


終了ステータス

存在しないディレクトリでcd ./を実行すると、chdir(TDIR)2は失敗するが、chdir("./")は成功するので、cdの終了ステータスは0に設定されます。
また、存在しないディレクトリでのchdir("../")も成功します。

コメントに記述されているようにPOSIXモードだと失敗しました。

bash --posix       <-bashをPOSIXモードで起動
$ mkdir test; cd test; 
$ rmdir ../test     <-カレントディレクトリを削除
$ cd ./
bash: cd: ./: No such file or directory
$ echo $?; pwd      
1             <-cdの終了ステータスが違う
pwd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory

エラーメッセージ

存在しないディレクトリでcd ./を実行すると、下記のようなエラーメッセージが出力されます。

cd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory

このメッセージを吐き出しているのは、the_current_working_directory4の再設定を行う際に呼び出されるget_working_directoryという関数です。
関数内部でgetcwd(カレントディレクトリのパスの取得)を実行し、存在しないディレクトリにいることが原因で失敗するので、エラーメッセージが出力されます。


pwdの出力

存在しないディレクトリでcd ./を実行した後、pwdを実行すると、./がふくまれたパスを出力されます。

これは、get_working_directoryが失敗し、カレントディレクトリが取得できていないことが原因です。
カレントディレクトリが取得できておらず、the_current_working_directoryが設定できていないため、TDIR3the_current_working_directoryとして設定されています。

$ pwd
/home/user42/test/./././/////./././/////././././/// 

getcwdが成功するディレクトリに来たタイミングでthe_current_working_directoryは正しい値に修正されます。

$ pwd
/home/user42/test/./././/////././././
$ cd ../
$ pwd
/home/user42

まとめ

存在しないディレクトリでのcd ./成功は、bashの親切設計が引き起こしている挙動でした。
エラーメッセージは、getcwdが失敗したことによる出力なので、終了ステータスには影響がないようです。


  1. UNIX系OSが備えるべきとされる仕様の規格 

  2. ./../といったディレクトリではない要素をパスの中から取り除く作業` 

  3. cdは、pwdで出力される値 + cdの引数で構成される物理パスの正規化に成功すると、chdirの引数(TDIR)として正規化されたパスを採用します。正規化に失敗(存在しないディレクトリが含まれているなど)すると、物理パスをTDIRとして採用します。 

  4. bashのソース内でカレントディレクトリとして使用される変数 


Viewing all articles
Browse latest Browse all 2863

Trending Articles