当执行`ls * .c`时,内部会发生什么?

akm*_*mal 1 linux shell wildcard linux-kernel

最近,我对Linux内部产生了非常大的兴趣,目前正在尝试了解它们的工作原理。

我知道当我打字 ls

  • opendir() -函数被调用;
  • readdir() -为目录数据存储中的每个目录条目调用的函数;
  • stat() -如果需要,可以调用函数以获得有关文件的其他信息。

如果我缺少某些东西或有错,请纠正我。

对我来说,神秘的部分是文件名扩展(globbing)。

我比较了 strace ls

open(".", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
getdents(3, /* 14 entries */, 32768)    = 440
getdents(3, /* 0 entries */, 32768)     = 0
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
write(1, "2q.c  ds.c  fglob  fnoglob\n", 272q.c  ds.c  fglob  fnoglob
Run Code Online (Sandbox Code Playgroud)

并且strace ls *.c

stat("2q.c", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
lstat("2q.c", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
stat("ds.c", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
lstat("ds.c", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
write(1, "2q.c  ds.c\n", 112q.c  ds.c
)            = 11
Run Code Online (Sandbox Code Playgroud)

从我有限的知识可以看出,在第一种情况下,它的确确实符合我的预期,open, stat其后是getdents

但是后面的一个问题对我来说尚不清楚,因为它已经存在了一系列与模式匹配的文件。该清单来自何处?

谢谢!

Kus*_*nda 5

在调用实用程序之前,命令行会在命令行上扩展命令行上的命令行模式。

您可以通过使用set -x以下命令在外壳中启用跟踪功能来查看:

$ set -x
$ ls -l f*
+ ls -l file1 file2 file3
-rw-r--r--  1 kk  wheel  0 May 11 16:49 file1
-rw-r--r--  1 kk  wheel  0 May 11 16:49 file2
-rw-r--r--  1 kk  wheel  0 May 11 16:49 file3
Run Code Online (Sandbox Code Playgroud)

如您所见,shell告诉您(在+提示符下)调用什么命令,并且此时它已经在命令行上扩展了模式。

ls命令不执行文件名遍历。实际上,如果您单引号括住保护其免受外壳破坏的模式,ls则必定会造成混淆:

$ ls -l 'f*'
+ ls -l f*
ls: f*: No such file or directory
Run Code Online (Sandbox Code Playgroud)

(除非当前目录中实际上确实有一些被称为f*)。