在哪里可以找到 ls 命令的 shell 脚本?

在哪里可以找到 ls 命令的 shell 脚本?

我试图了解该ls命令是如何工作的,并且我假设有一个 shell 脚本定义了ls文件系统中的某个位置。这对吗?如果有的话,我在哪里可以找到它?

答案1

ls使用opendir()readdir()逐步浏览目录中的所有文件。如果它需要有关其中之一的更多信息,它会调用stat().当然,请阅读源代码,但一个非常方便的快捷方式是:

# strace ls

有几个评论的关键部分是:

获取目录条目

open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3
fcntl64(3, F_GETFD)                     = 0x1 (flags FD_CLOEXEC)
getdents64(3, /* 53 entries */, 32768)  = 1744
getdents64(3, /* 0 entries */, 32768)   = 0
close(3)                                = 0

验证 stdout 是字符设备

fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 0), ...}) = 0

将标准输入映射到内存中。 (不知道为什么,看源码)

mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0xb73ff000

将目录条目写入 stdout 和总结

write(1, "bin  Desktop  Documents  Downloa"..., 91bin  Desktop
Documents  Download  Music  Pictures  Public  public_html  Templates
Videos
) = 91
close(1)                                = 0
munmap(0xb73ff000, 4096)                = 0
close(2)                                = 0
exit_group(0)                           = ?

答案2

ls不是 shell 脚本,如果你发出file命令,你会知道它是一个 ELF 64 位 LSB 可执行文件:

$ type -a ls
ls is aliased to `ls --color=auto'
ls is /usr/bin/ls #<---- now we know the file path of `ls`
ls is /bin/ls
$ 
$ file /usr/bin/ls
/usr/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=ddf8cdb3f1fd2e8263637b7c8ccea84fbf41ee3c, stripped
$ 

网上可以找到源码这里

或者,如果您的发行版是基于 RPM 的 Linux 发行版 + dnf,那么您可以:

$ rpm -qf /usr/bin/ls
coreutils-8.22-22.fc21.x86_64 #so now we know the package name is coreutils
$ sudo dnf whatprovides /usr/bin/ls #alternative way
Using metadata from Mon May 16 02:39:55 2016 (1 day, 23:03:50 hours old)
coreutils-8.22-22.fc21.x86_64 : A set of basic GNU tools commonly used in shell scripts
Repo        : @System

coreutils-8.22-19.fc21.x86_64 : A set of basic GNU tools commonly used in shell scripts
Repo        : fedora

coreutils-8.22-22.fc21.x86_64 : A set of basic GNU tools commonly used in shell scripts
Repo        : updates

$ 
$ mkdir coreutils #optional
$ cd coreutils #optional
$ sudo dnf download --source coreutils
...
$ rpm2cpio coreutils-8.22-22.fc21.src.rpm |cpio -idmv
...
$ sudo rm coreutils-8.22-22.fc21.src.rpm #optional
$ unp coreutils-8.22.tar.xz
...
$ rm coreutils-8.22.tar.xz #optional
$ cd coreutils-8.22/
$ find . -iname 'ls*'
./lib/lseek.c
./lib/lstat.c
./src/ls.c  #<---- now we know ls.c is here
./src/ls-vdir.c
./src/ls.h
./src/ls-ls.c
./src/ls-dir.c
./man/ls.x
./tests/ls
./tests/misc/ls-misc.pl
./tests/misc/ls-time.sh
./m4/ls-mntd-fs.m4
./m4/lstat.m4
./m4/lseek.m4
$ vi ./src/ls.c

笔记:

  1. coreutils-8.22-22.fc21.src.rpm 是我的,您的包编号可能有所不同。

  2. 有些命令如type -a historyreturn“history is a shellbuiltin”,你应该查看当前的shell源代码,即rpm -qf `readlink -f /proc/$$/exe`(Detect current shell by command is棘手的比你想象的要多,这个技巧在 shell 中不起作用fish

  3. 在 csh/tcsh shell 中,您应该使用,where history因为没有这样的type命令。可以找到更多详细信息这里

  4. 您可能还有兴趣尝试通配符,例如repoquery --resolve --archlist=src '*compress*'包含未安装的软件包(如果查询命令如“*uncompress*”,请小心,在这种情况下,如果第一次尝试“*uncompress*”,您需要删除前缀“un”以缩小范围失败的)。上面的输出repoquery需要删除中间0:并可选择后缀.rpm获取可用于搜索的正确全名http://rpm.pbone.net,例如 ncompress-0:4.2.4.4-3.fc21.src 将其更改为 ncompress-4.2.4.4-3.fc21.src.rpm

  5. dnf下载源码时可以开启镜像调试,以防镜像服务器宕机。看

[更新]

如果您像我一样由于无效的存储库而出现 rpm 错误,这就是我修复它的方法:

$ sudo dnf config-manager --set-enabled '*' #Enable all repos, at anytime, check with `sudo dnf repolist all`
$ repoquery --resolve --archlist=src '*compress*'                                       
Could not match packages: failure: repodata/repomd.xml from rpmfusion-free-rawhide-source: [Errno 256] No more mirrors to try.
http://free.nchc.org.tw/rpmfusion/free/fedora/development/rawhide/source/SRPMS/repodata/repomd.xml: [Errno 14] HTTP Error 404 - Not Found                               
...
$ repoquery --resolve --archlist=src --enablerepo='*source' --disablerepo='rpmfusion-free-rawhide-source'  '*compress*' #not works too
...
$ sudo yum-config-manager --save --disablerepo=rpmfusion-nonfree-rawhide-source #for unknown reason, it doesn't work
$ sudo dnf config-manager --set-disabled rpmfusion-free-rawhide-source #for unknown reason, it doesn't work
$ grep -rnIH -D skip --color=always rpmfusion-free-rawhide-source /etc/yum.repos.d/
/etc/yum.repos.d/rpmfusion-free-rawhide.repo:17:[rpmfusion-free-rawhide-source]
$ sudo vi /etc/yum.repos.d/rpmfusion-free-rawhide.repo #Edit rpmfusion-free-rawhide-source from enabled=1 to enabled=0
$ repoquery --resolve --archlist=src  '*compress*'#now should works :) repeat the `grep and vi` steps above if got error in other repos, in my case i have to disable rpmfusion-nonfree-rawhide-source too.

p/s:将标题从 [rpmfusion-free-rawhide-source] 编辑为 [rpmfusion-free-rawhide-source禁用] hack 应该使 --enablerepo='*source' 有效,尽管到目前为止我发现这是不必要的,因为我已经在第一个命令中启用了所有存储库。

答案3

我不知道这是否是一个答案,因为 ls 是用 C 编写的,但您可以编写一个 shell 脚本来使用 for 循环执行“ls”:

for f in *;do echo $f;完毕

它在一些静态 shell 中也很有用......

相关内容