16
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-03-18

##環境

$ 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. ./../といったディレクトリではない要素をパスの中から取り除く作業` 2

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

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

16
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?