Wo finde ich das Shell-Skript für den Befehl ls?

Wo finde ich das Shell-Skript für den Befehl ls?

Ich versuche zu verstehen, wie der lsBefehl funktioniert, und gehe davon aus, dass es lsirgendwo im Dateisystem ein Shell-Skript gibt, das dies definiert. Ist das richtig? Wenn ja, wo kann ich es finden?

Antwort1

lsverwendet opendir()und readdir()um durch alle Dateien im Verzeichnis zu blättern. Wenn es mehr Informationen über eine davon benötigt, ruft es auf stat(). Lesen Sie natürlich den Quellcode, aber eine sehr praktische Abkürzung ist:

# strace ls

Der wichtigste Teil mit ein paar Kommentaren ist:

Abrufen der Verzeichniseinträge

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

Überprüfen Sie, ob es sich bei stdout um ein Zeichengerät handelt

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

stdin in den Speicher mappen. (Nicht sicher, warum, siehe Quelle)

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

schreibe die Verzeichniseinträge auf stdout und beende

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)                           = ?

Antwort2

lsist kein Shell-Skript. Wenn Sie fileden Befehl eingeben, wissen Sie, dass es sich um eine ausführbare ELF 64-Bit LSB-Datei handelt:

$ 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
$ 

Den Online-Quellcode finden SieHier.

Oder wenn Ihre Distribution auf RPM-basierten Linux-Distributionen + basiert dnf, dann können Sie:

$ 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

Notiz:

  1. coreutils-8.22-22.fc21.src.rpm ist von mir, Ihre Paketnummer kann abweichen.

  2. Bei manchen Befehlen wie type -a historyreturn "history is a shell builtin" sollten Sie sich den aktuellen Shell-Quellcode ansehen, d. h. rpm -qf `readlink -f /proc/$$/exe`(Detect current shell by command istschwierigals Sie vielleicht denken, dieser Trick funktioniert nicht in fishder Shell)

  3. In der csh/tcsh-Shell sollten Sie where historybecause no such typecommand verwenden. Weitere Details finden SieHier.

  4. Sie könnten auch Wildcards ausprobieren, repoquery --resolve --archlist=src '*compress*'um z. B. nicht installierte Pakete einzuschließen (Seien Sie vorsichtig bei Abfragebefehlen wie '*uncompress*', in diesem Fall müssen Sie das Präfix 'un' entfernen, um die Suche einzugrenzen, wenn der erste Versuch '*uncompress*' fehlgeschlagen ist). Die Ausgabe von repoqueryoben muss die mittleren0:und optional Postfix mit.rpmum den richtigen vollständigen Namen zu erhalten, mit dem Sie suchen können inhttp://rpm.pbone.net, zB ncompress-0:4.2.4.4-3.fc21.src ändern Sie es in ncompress-4.2.4.4-3.fc21.src.rpm

  5. Sie können Mirror-Debugging aktivieren, wenn die Quelle nicht heruntergeladen werden kann, falls der Mirror-Server ausfällt. SieheDas.

[AKTUALISIEREN]

Falls Sie wie ich einen RPM-Fehler aufgrund ungültiger Repos haben, habe ich ihn folgendermaßen behoben:

$ 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.:Bearbeiten Sie den Titel von [rpmfusion-free-rawhide-source] in [rpmfusion-free-rawhide-sourceDEAKTIVIEREN] Der Hack sollte dafür sorgen, dass --enablerepo='*source' funktioniert, allerdings habe ich bisher festgestellt, dass dies unnötig ist, da ich alle Repos bereits im ersten Befehl aktiviere.

Antwort3

Ich weiß nicht, ob das eine Antwort ist, weil ls in C geschrieben ist, aber Sie können ein Shell-Skript schreiben, um ein „ls“ mithilfe der For-Schleife auszuführen:

für f in *;mache echo $f; fertig

Es ist auch in einigen statischen Shells nützlich ...

verwandte Informationen