
Ich versuche zu verstehen, wie der ls
Befehl funktioniert, und gehe davon aus, dass es ls
irgendwo im Dateisystem ein Shell-Skript gibt, das dies definiert. Ist das richtig? Wenn ja, wo kann ich es finden?
Antwort1
ls
verwendet 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
ls
ist kein Shell-Skript. Wenn Sie file
den 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:
coreutils-8.22-22.fc21.src.rpm ist von mir, Ihre Paketnummer kann abweichen.
Bei manchen Befehlen wie
type -a history
return "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 infish
der Shell)In der csh/tcsh-Shell sollten Sie
where history
because no suchtype
command verwenden. Weitere Details finden SieHier.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 vonrepoquery
oben 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.rpmSie 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 ...