Ich habe nur versucht, alle Verzeichnisse und Dateien im aktuellen Verzeichnis aufzulisten und auch zu schreiben, ob es sich um Dateien oder Verzeichnisse handelt, mit dem folgenden Befehl:
find -exec echo `echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi` \;
Ich weiß, dass es ein dummer Befehl ist, ich kann andere Dinge wie -type f
oder verwenden -type d
, aber ich möchte erfahren, warum dieser Code nicht wie erwartet funktioniert hat. Es druckt nur das Verzeichnis für alle. Zum Beispiel während die Ausgabe von find
ist:
.
./dir
./dir/file
Ausgabe meines Codes ist:
. : directory
./dir : directory
./dir/file : directory
Und Ausgabe von
echo `echo dir/file : ;if [ -f dir/file ]; then echo file; else echo directory;fi`
ist
dir/file : file
Ich arbeite an Ubuntu 14.10
und benutzefind (GNU findutils) 4.4.2
bash
shell
find
command-substitution
Esref
quelle
quelle
find -exec bash -c 'echo -n "{} : ";if [ -f "{}" ]; then echo file; else echo directory;fi' \;
"{}"
. Warum benutzt duecho
zweimal?echo "{}" : ;if [ -f "{}" ]; then echo file; else echo directory;fi
\;Antworten:
Zunächst führt Ihr Snippet den Befehl aus
weil es seine Ausgabe benötigt, um die Befehlssubstitution auszuwerten. Da keine Datei benannt ist
{}
, wird die Ausgabe erzeugtDann wird der
find
Befehl mit den Argumenten ausgeführt wird-exec
,echo
,{}
,:
,directory
, so dass für jede Datei, gibt er die Dateinamen gefolgt von einem Leerzeichen und: directory
.Was Sie tatsächlich tun möchten, ist, das Shell-Snippet
echo {} :; …
für jede von gefundene Datei auszuführenfind
. Dieses Snippet muss von einer Shell ausgeführt werden, die von erzeugt wirdfind
, nicht von der Shell, die gestartet wirdfind
, da sie Daten vonfind
ihrer Befehlszeile empfängt . Daher müssen Sie anweisenfind
, eine Shell auszuführen:Das ist besser, aber immer noch nicht richtig. Es funktioniert mit einigen (nicht allen)
find
Implementierungen, wenn Ihre Dateinamen keine Sonderzeichen enthalten. Da Sie jedoch den Dateinamen in einem Shell-Skript interpolieren, können Dateinamen beliebige Shell-Befehle ausführen, z Eine Datei namens$(rm -rf /)
dann wird der Befehlrm -rf /
ausgeführt. Um Dateinamen an das Skript zu übergeben, übergeben Sie sie als separate Argumente.Auch der erste
echo
druckt eine neue Zeile nach dem Doppelpunkt. Verwenden Sieecho -n
(wenn Ihre Shell dies unterstützt) oderprintf
um dies zu vermeiden.Sie können
-exec … {} +
Shell-Aufrufe gruppieren, was schneller ist.quelle
Eine andere Möglichkeit,
if; then; else; fi
zusammen mit auszuführen,find
ist:quelle