`Dir.chdir("~/filename")`などで`~`が展開されるか否かの記述があった方がよい。
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"))とすれば展開できる。
気になったので、いろいろ調べてみました。
まず 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 には記述ないですが、実装は ~ を展開しないようなので、参考くらいの記述があるとちょうどよさそうに思いました。
シェル (たとえば bash) でも cd コマンドは展開しないので (展開するのはシェルのコマンドライン処理の方)、わざわざ説明を入れるなら、 chdir が ~ を展開するプログラミング言語の例がほしいです。
もしそういう言語がないのなら、間違いやすい例として実行例に入れるぐらいでもいいのかなと思いました。
$ mkdir -p ~/tmp
$ cd '~/tmp'
bash: cd: ~/tmp: No such file or directory
~ を展開する言語は、あまりないような気がします。
>>> 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
なるほど、実行例に入れるのはいい気がします。 追記する形で書くとすると、こんな感じでしょうか 🤔
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
良さそうに思いました。
実際に ~ というディレクトリが存在するときの例もあると展開されない理由がわかりやすそうですが、そこまで書いてしまうと例が複雑になりすぎるので、そこまではなくても良いかなと思いました。
ありがとうございます。
実際に ~ というディレクトリが存在するときの例については、なくてもよいかなと思います。 ~ と $HOME のどちらかをわかるように記述しようとすると、相当に複雑になりそうです。
---
それでは、上記内容で PR を作成してみます。