doctree icon indicating copy to clipboard operation
doctree copied to clipboard

`Dir.chdir("~/filename")`などで`~`が展開されるか否かの記述があった方がよい。

Open hyuki opened this issue 2 years ago • 5 comments

https://docs.ruby-lang.org/ja/latest/method/Dir/s/chdir.html

Dir.chdir("~/filename")などで~が展開されるか否かの記述があった方がよい。

Ruby 3.0.2では展開されないようだ。

Dir.chdir(File.expand_path("~/filename"))とすれば展開できる。

hyuki avatar May 13 '23 21:05 hyuki

気になったので、いろいろ調べてみました。

まず RDoc には、 Dir.chdir("~/filename") などで ~ が展開される/されない、といった記述は見当たらないですね。 https://docs.ruby-lang.org/en/3.3/Dir.html#method-c-chdir

File.expand_path("~/filename") は、 s_expand_path v3_3_6 file.c#L4132-L4164 rb_file_s_expand_path v3_3_6 file.c#L4125-L4130 rb_file_expand_path v3_3_6 file.c#L4112-L4117 expand_path v3_3_6 file.c#L4099-L4100 rb_file_expand_path_internal v3_3_6 file.c#L3740-L4087

の流れで、最終的に ~ が展開されるようです。 WIN32 の場合は別の処理になるようですが…… rb_file_expand_path_internal v3_3_6 win32/file.c#L275-L582

Dir.chdir("~/filename") は、 dir_s_chdir v3_3_6 dir.c#L1108-L1189 chdir_path v3_3_6 dir.c#L1078-L1106 nogvl_chdir v3_3_6 dir.c#L1029-L1035

の流れで、 ~ が展開されないまま chdir(2) に渡されるようです。

実際に Dir.chdir("~/filename") が失敗する理由は Errno::ENOENT です。同じように chdir("~/filename")Errno::ENOENT で失敗します。

irb(main):001> Dir.chdir("~/filename")
(irb):1:in `chdir': No such file or directory @ chdir_path - ~/filename (Errno::ENOENT)
	from (irb):1:in `<main>'
	from <internal:kernel>:187:in `loop'
	from /usr/local/lib/ruby/gems/3.3.0/gems/irb-1.13.1/exe/irb:9:in `<top (required)>'
	from /usr/local/bin/irb:25:in `load'
	from /usr/local/bin/irb:25:in `<main>'
irb(main):002> 
$ cat << EOF > main.c
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
int main() {
  int ret = chdir("~/filename");
  printf("%d, %d, %d\n", ret, errno, ENOENT);
  return 0;
}
EOF
$ gcc -o main.out main.c
$ ./main.out 
-1, 2, 2
$

---

Dir.chdir("~/filename") などで ~ が展開されるか否かの記述があった方がよい。

RDoc には記述ないですが、実装は ~ を展開しないようなので、参考くらいの記述があるとちょうどよさそうに思いました。

tmyksj avatar Nov 14 '24 13:11 tmyksj

シェル (たとえば bash) でも cd コマンドは展開しないので (展開するのはシェルのコマンドライン処理の方)、わざわざ説明を入れるなら、 chdir~ を展開するプログラミング言語の例がほしいです。

もしそういう言語がないのなら、間違いやすい例として実行例に入れるぐらいでもいいのかなと思いました。

$ mkdir -p ~/tmp
$ cd '~/tmp'
bash: cd: ~/tmp: No such file or directory

znz avatar Nov 14 '24 22:11 znz

~ を展開する言語は、あまりないような気がします。

>>> import os
>>> os.chdir("~/filename")
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    os.chdir("~/filename")
    ~~~~~~~~^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '~/filename'
>>> 
php > chdir("~/filename");

Warning: chdir(): No such file or directory (errno 2) in php shell code on line 1
php > 
$ cat << EOF > main.go
package main
import (
    "log"
    "os"
)
func main() {
    err := os.Chdir("~/filename")
    if err != nil {
        log.Fatal(err)
    }
}
EOF
$ go run .
2024/11/15 13:56:15 chdir ~/filename: no such file or directory
exit status 1
$

もしそういう言語がないのなら、間違いやすい例として実行例に入れるぐらいでもいいのかなと思いました。

なるほど、実行例に入れるのはいい気がします。 追記する形で書くとすると、こんな感じでしょうか :thinking:

Dir.chdir("/var/spool/mail")
p Dir.pwd                    #=> "/var/spool/mail"
Dir.chdir("/tmp") do
  p Dir.pwd                  #=> "/tmp"
end 
p Dir.pwd                    #=> "/var/spool/mail"

# ~ は展開されない
Dir.chdir('~/foo')           # => Errno::ENOENT

tmyksj avatar Nov 15 '24 14:11 tmyksj

なるほど、実行例に入れるのはいい気がします。 追記する形で書くとすると、こんな感じでしょうか 🤔

Dir.chdir("/var/spool/mail")
p Dir.pwd                    #=> "/var/spool/mail"
Dir.chdir("/tmp") do
  p Dir.pwd                  #=> "/tmp"
end 
p Dir.pwd                    #=> "/var/spool/mail"

# ~ は展開されない
Dir.chdir('~/foo')           # => Errno::ENOENT

良さそうに思いました。

実際に ~ というディレクトリが存在するときの例もあると展開されない理由がわかりやすそうですが、そこまで書いてしまうと例が複雑になりすぎるので、そこまではなくても良いかなと思いました。

znz avatar Nov 26 '24 08:11 znz

ありがとうございます。

実際に ~ というディレクトリが存在するときの例については、なくてもよいかなと思います。 ~$HOME のどちらかをわかるように記述しようとすると、相当に複雑になりそうです。

---

それでは、上記内容で PR を作成してみます。

tmyksj avatar Nov 28 '24 10:11 tmyksj