Ich sehe durchweg Antworten, die diesen Link mit der definitiven Aussage "Don't parse ls
!" Zitieren. Das stört mich aus mehreren Gründen:
Es sieht so aus, als ob die Informationen in diesem Link mit wenig Bedenken allgemein akzeptiert wurden, obwohl ich zumindest ein paar Fehler beim gelegentlichen Lesen herausgreifen kann.
Es scheint auch, als hätten die in diesem Link genannten Probleme keinen Wunsch nach einer Lösung geweckt.
Ab dem ersten Absatz:
... wenn Sie
[ls]
nach einer Liste von Dateien fragen , gibt es ein großes Problem: Unix lässt fast jedes Zeichen in einem Dateinamen zu, einschließlich Leerzeichen, Zeilenumbrüchen, Kommas, Pipe-Symbolen und so ziemlich allem, was Sie jemals als verwenden würden Trennzeichen außer NUL. ...ls
trennt Dateinamen mit Zeilenumbrüchen. Dies ist in Ordnung, bis Sie eine Datei mit einer neuen Zeile im Namen haben. Und da mir keine Implementierung bekannt istls
, mit der Sie Dateinamen mit NUL-Zeichen anstelle von Zeilenumbrüchen abschließen können, ist es uns nicht möglich, eine Liste sicherer Dateinamen zu erhaltenls
.
Schade, oder? Wie immer können wir damit umgehen ein Newline gelisteten Datensatz für Daten beendet , die Zeilenumbrüche enthalten könnten? Nun, wenn die Leute, die auf dieser Website Fragen beantworteten, solche Dinge nicht täglich taten, könnte ich denken, dass wir in Schwierigkeiten steckten.
Die Wahrheit ist jedoch, dass die meisten ls
Implementierungen tatsächlich eine sehr einfache API zum Parsen ihrer Ausgabe bereitstellen, und wir haben es alle die ganze Zeit gemacht, ohne es überhaupt zu merken. Sie können einen Dateinamen nicht nur mit null beenden, sondern auch mit null oder einer beliebigen anderen Zeichenfolge beginnen. Außerdem können Sie diese beliebigen Zeichenfolgen pro Dateityp zuweisen . Beachten Sie bitte:
LS_COLORS='lc=\0:rc=:ec=\0\0\0:fi=:di=:' ls -l --color=always | cat -A
total 4$
drwxr-xr-x 1 mikeserv mikeserv 0 Jul 10 01:05 ^@^@^@^@dir^@^@^@/$
-rw-r--r-- 1 mikeserv mikeserv 4 Jul 10 02:18 ^@file1^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 01:08 ^@file2^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 02:27 ^@new$
line$
file^@^@^@$
^@
Sehen Sie dies für mehr.
Jetzt ist es der nächste Teil dieses Artikels, der mich wirklich begeistert:
$ ls -l
total 8
-rw-r----- 1 lhunath lhunath 19 Mar 27 10:47 a
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a?newline
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a space
Das Problem ist, dass
ls
weder Sie noch der Computer anhand der Ausgabe von erkennen können, welche Teile davon einen Dateinamen darstellen. Ist es jedes Wort? Nein, ist es jede Zeile? Nein. Es gibt keine richtige Antwort auf diese Frage außer: Sie können es nicht sagen.
ls
Beachten Sie auch, wie manchmal Ihre Dateinamendaten verstümmelt werden (in unserem Fall wurde das\n
Zeichen zwischen den Wörtern "a" und "newline" in ein Fragezeichen umgewandelt ......
Wenn Sie nur alle Dateien im aktuellen Verzeichnis durchlaufen möchten, verwenden Sie eine
for
Schleife und einen Glob:
for f in *; do
[[ -e $f ]] || continue
...
done
Der Autor nennt es unleserliche Dateinamen, wenn er ls
eine Liste von Dateinamen zurückgibt, die Shell-Globs enthalten, und empfiehlt dann , ein Shell-Glob zu verwenden, um eine Dateiliste abzurufen!
Folgendes berücksichtigen:
printf 'touch ./"%b"\n' "file\nname" "f i l e n a m e" |
. /dev/stdin
ls -1q
f i l e n a m e
file?name
IFS="
" ; printf "'%s'\n" $(ls -1q)
'f i l e n a m e'
'file
name'
POSIX definiert die Operanden -1
und folgendermaßen -q
ls
:
-q
- Erzwingen Sie, dass jede Instanz von nicht druckbaren Dateinamenzeichen und<tab>
s als Fragezeichen ('?'
) geschrieben wird. Implementierungen bieten diese Option möglicherweise standardmäßig an, wenn die Ausgabe an ein Endgerät erfolgt.
-1
- (Die numerische Ziffer Eins.) Erzwingt die Ausgabe eines Eintrags pro Zeile.
Das Globbing ist nicht ohne Probleme - es ?
stimmt mit jedem Zeichen überein , sodass mehrere Übereinstimmungsergebnisse ?
in einer Liste mehrmals mit derselben Datei übereinstimmen . Das ist leicht zu handhaben.
Obwohl es nicht darum geht, wie man das macht - es braucht doch nicht viel, und es wird unten gezeigt -, war ich daran interessiert, warum nicht . Meiner Meinung nach wurde die beste Antwort auf diese Frage angenommen. Ich würde vorschlagen, dass Sie versuchen, sich häufiger darauf zu konzentrieren, den Leuten zu sagen, was sie können , als auf das, was sie nicht können. Sie sind viel weniger wahrscheinlich, wie ich denke, zumindest als falsch erwiesen zu werden.
Aber warum sollte man es überhaupt versuchen? Zugegeben, meine Hauptmotivation war, dass andere mir immer wieder sagten, ich könne es nicht. Ich weiß sehr gut, dass die ls
Ausgabe so regelmäßig und vorhersehbar ist, wie Sie es wünschen können, solange Sie wissen, wonach Sie suchen müssen. Fehlinformationen stören mich mehr als die meisten anderen Dinge.
Die Wahrheit ist jedoch, dass ich mit Ausnahme der Antworten von Patrick und Wumpus Q. Wumbley (trotz des großartigen Griffs des letzteren) die meisten Informationen in den Antworten als größtenteils richtig betrachte - ein Shell Glob ist einfacher zu verwenden und im Allgemeinen effektiver beim Durchsuchen des aktuellen Verzeichnisses als beim Parsen ls
. Sie sind jedoch nicht zumindest in meiner Hinsicht Grund genug , um zu rechtfertigen , entweder die falschen Informationen in dem Artikel zitiert ausbreitende oben noch sind sie akzeptabel Rechtfertigung „ nie zu analysieren ls
. “
Bitte beachten Sie, dass die inkonsistenten Ergebnisse von Patricks Antwort größtenteils darauf zurückzuführen sind, dass er sie zsh
dann verwendet bash
. zsh
- Standardmäßig - Ersetzt keine wortgeteilten $(
Befehle )
auf tragbare Weise. Also, wenn er fragt, wo sind die restlichen Dateien hingegangen? Die Antwort auf diese Frage ist, dass Ihre Muschel sie gefressen hat. Aus diesem Grund müssen Sie die SH_WORD_SPLIT
Variable festlegen , wenn Sie zsh
portablen Shell-Code verwenden und damit umgehen. Ich halte es für furchtbar irreführend, dass er dies in seiner Antwort nicht zur Kenntnis genommen hat.
Die Antwort von Wumpus lässt sich für mich nicht berechnen - in einem Listenkontext ist der ?
Charakter ein Shell-Glob. Ich weiß nicht, wie ich das sonst sagen soll.
Um einen Fall mit mehreren Ergebnissen zu behandeln, müssen Sie die Gier des Globus einschränken. Im Folgenden wird nur eine Testbasis mit schrecklichen Dateinamen erstellt und für Sie angezeigt:
{ printf %b $(printf \\%04o `seq 0 127`) |
sed "/[^[-b]*/s///g
s/\(.\)\(.\)/touch '?\v\2' '\1\t\2' '\1\n\2'\n/g" |
. /dev/stdin
echo '`ls` ?QUOTED `-m` COMMA,SEP'
ls -qm
echo ; echo 'NOW LITERAL - COMMA,SEP'
ls -m | cat
( set -- * ; printf "\nFILE COUNT: %s\n" $# )
}
AUSGABE
`ls` ?QUOTED `-m` COMMA,SEP
??\, ??^, ??`, ??b, [?\, [?\, ]?^, ]?^, _?`, _?`, a?b, a?b
NOW LITERAL - COMMA,SEP
?
\, ?
^, ?
`, ?
b, [ \, [
\, ] ^, ]
^, _ `, _
`, a b, a
b
FILE COUNT: 12
Jetzt werde ich sicher jedes Zeichen , das kein ist /slash
, -dash
, :colon
, oder alphanumerischen Zeichen in einer Shell - Glob dann sort -u
die Liste für eindeutige Ergebnisse. Dies ist sicher, da ls
bereits alle nicht druckbaren Zeichen für uns gespeichert wurden. Sehen:
for f in $(
ls -1q |
sed 's|[^-:/[:alnum:]]|[!-\\:[:alnum:]]|g' |
sort -u | {
echo 'PRE-GLOB:' >&2
tee /dev/fd/2
printf '\nPOST-GLOB:\n' >&2
}
) ; do
printf "FILE #$((i=i+1)): '%s'\n" "$f"
done
AUSGABE:
PRE-GLOB:
[!-\:[:alnum:]][!-\:[:alnum:]][!-\:[:alnum:]]
[!-\:[:alnum:]][!-\:[:alnum:]]b
a[!-\:[:alnum:]]b
POST-GLOB:
FILE #1: '?
\'
FILE #2: '?
^'
FILE #3: '?
`'
FILE #4: '[ \'
FILE #5: '[
\'
FILE #6: '] ^'
FILE #7: ']
^'
FILE #8: '_ `'
FILE #9: '_
`'
FILE #10: '?
b'
FILE #11: 'a b'
FILE #12: 'a
b'
Im Folgenden gehe ich erneut auf das Problem ein, wende jedoch eine andere Methode an. Denken Sie daran, dass neben \0
Null das /
ASCII-Zeichen das einzige Byte ist, das in einem Pfadnamen verboten ist. Ich lege hier Globs beiseite und kombiniere stattdessen die von POSIX angegebene -d
Option für ls
und das von POSIX angegebene -exec $cmd {} +
Konstrukt für find
. Da find
immer nur eine /
Datei in natürlicher Reihenfolge ausgegeben wird, wird im Folgenden eine rekursive und zuverlässig begrenzte Dateiliste mit allen Eintragsinformationen für jeden Eintrag bereitgestellt. Stellen Sie sich vor, was Sie mit so etwas machen könnten:
#v#note: to do this fully portably substitute an actual newline \#v#
#v#for 'n' for the first sed invocation#v#
cd ..
find ././ -exec ls -1ldin {} + |
sed -e '\| *\./\./|{s||\n.///|;i///' -e \} |
sed 'N;s|\(\n\)///|///\1|;$s|$|///|;P;D'
###OUTPUT
152398 drwxr-xr-x 1 1000 1000 72 Jun 24 14:49
.///testls///
152399 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
\///
152402 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
^///
152405 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
`///
...
ls -i
kann sehr nützlich sein - besonders wenn es um die Eindeutigkeit des Ergebnisses geht.
ls -1iq |
sed '/ .*/s///;s/^/-inum /;$!s/$/ -o /' |
tr -d '\n' |
xargs find
Dies sind nur die tragbarsten Mittel, die ich mir vorstellen kann. Mit GNU können ls
Sie Folgendes tun:
ls --quoting-style=WORD
Und zum Schluss noch eine viel einfachere Methode zum Parsenls
, die ich häufig verwende, wenn ich Inode-Nummern benötige:
ls -1iq | grep -o '^ *[0-9]*'
Das gibt nur Inode-Nummern zurück - eine weitere praktische POSIX-Option.
time bash -c 'for i in {1..1000}; do ls -R &>/dev/null; done'
= 3,18s vstime bash -c 'for i in {1..1000}; do echo **/* >/dev/null; done'
= 1,28sstat
in meiner Antwort überprüft, ob jede Datei vorhanden ist. Dein bisschen unten mit demsed
Ding klappt nicht.ls
? Was Sie beschreiben, ist sehr schwer. Ich muss es dekonstruieren, um alles zu verstehen, und ich bin ein relativ kompetenter Benutzer. Sie können unmöglich erwarten, dass Ihr durchschnittlicher Joe mit so etwas fertig wird.ls
Ausgabe falsch ist, wurden im ursprünglichen Link (und an vielen anderen Stellen) gut behandelt. Diese Frage wäre vernünftig gewesen, wenn OP um Hilfe gebeten hätte, es zu verstehen, aber stattdessen versucht OP einfach zu beweisen, dass seine falsche Verwendung in Ordnung ist.parsing ls is bad
. Tunfor something in $(command)
und ich auf Wort-Splitting genaue Ergebnisse zu erhalten , ist schlecht für die große Mehrheit dercommand's
der nicht einfachen Ausgang.Antworten:
Davon bin ich überhaupt nicht überzeugt, aber nehmen wir an, Sie könnten , wenn Sie bereit sind, sich genug Mühe zu geben, die Ergebnisse
ls
auch gegenüber einem "Gegner" - jemandem, der es tut - zuverlässig analysieren kennt den von Ihnen geschriebenen Code und wählt absichtlich Dateinamen aus, um ihn zu knacken.Selbst wenn Sie das könnten, wäre es immer noch eine schlechte Idee .
Borowski-Shell ist keine gute Sprache. Es sollte nicht für komplizierte Dinge verwendet werden, es sei denn, extreme Portabilität ist wichtiger als irgendein anderer Faktor (z
autoconf
. B. ).Ich behaupte, wenn Sie mit einem Problem konfrontiert sind, bei dem das Parsen der Ausgabe von
ls
wie der Pfad des geringsten Widerstands für ein Shell-Skript erscheint, ist dies ein starkes Indiz dafür, dass alles, was Sie tun, für Shell zu kompliziert ist und Sie das Ganze in neu schreiben sollten Perl oder Python. Hier ist Ihr letztes Programm in Python:Dies hat keinerlei Probleme mit ungewöhnlichen Zeichen in Dateinamen - die Ausgabe ist mehrdeutig, genauso wie die Ausgabe von
ls
mehrdeutig ist, aber das würde in einem "echten" Programm (im Gegensatz zu einer Demo wie dieser) keine Rolle spielen benutze das Ergebnis vonos.path.join(subdir, f)
direkt.Ebenso wichtig und im krassen Gegensatz zu dem, was Sie geschrieben haben, wird es in sechs Monaten immer noch Sinn machen, und es wird leicht zu modifizieren sein, wenn Sie es brauchen, um etwas etwas anderes zu tun. Nehmen wir zur Veranschaulichung an, Sie müssen Punktdateien und Editor-Backups ausschließen und alles in alphabetischer Reihenfolge nach dem Basisnamen verarbeiten:
quelle
for in | for in
von Rekursion? Ich bin mir nicht sicher. Auch wenn es so ist, kann es doch nicht mehr als eins sein, oder? Dies ist die einzige Antwort, die mir bisher Sinn macht.for
Schleifen.os.walk
hinter den kulissen muss man sich nicht mehr darum kümmern, als sich darum zu sorgen, wiels
oder wie manfind
intern arbeitet.os.walk
ein Generatorobjekt zurückgegeben . Generatoren sind Pythons Version von Lazy Lists. Jedes Mal, wenn die äußere for-Schleife iteriert, wird der Generator aufgerufen und liefert den Inhalt eines anderen Unterverzeichnisses. Gleichwertige Funktionalität in Perl istFile::Find
, wenn das hilft.ls
Ausgabe zu vermeiden .Auf diesen Link wird häufig verwiesen, da die Informationen absolut korrekt sind und schon sehr lange vorhanden sind.
ls
Ersetzt nicht druckbare Zeichen durch Glob-Zeichen. Ja, aber diese Zeichen sind nicht im tatsächlichen Dateinamen enthalten. Warum ist das wichtig? 2 Gründe:Zum Beispiel:
Beachten Sie, wie wir 2 Dateien haben, die genau gleich aussehen. Wie werden Sie sie unterscheiden, wenn beide als dargestellt werden
a?b
?Hier gibt es einen Unterschied. Wenn Sie einen Glob zurückerhalten (siehe Abbildung), stimmt dieser Glob möglicherweise mit mehr als einer Datei überein. Wenn Sie jedoch die Ergebnisse durchlaufen, die mit einem Glob übereinstimmen, erhalten Sie die genaue Datei und nicht einen Glob zurück.
Zum Beispiel:
Beachten Sie, wie die
xxd
Ausgabe zeigt, dass$file
die unformatierten Zeichen\t
und\n
nicht enthalten?
.Wenn Sie verwenden
ls
, erhalten Sie stattdessen Folgendes:"Ich werde sowieso iterieren, warum nicht benutzen
ls
?"Dein Beispiel, das du gegeben hast, funktioniert nicht wirklich. Es sieht aus wie es funktioniert, aber es funktioniert nicht.
Damit meine ich:
Ich habe ein Verzeichnis mit einer Reihe von Dateinamen erstellt:
Wenn ich Ihren Code ausführe, erhalte ich Folgendes:
Wo sind die restlichen Dateien geblieben?
Lass es uns stattdessen versuchen:
Verwenden wir nun ein aktuelles Glob:
Mit Bash
Das obige Beispiel war mit meiner normalen Shell, zsh. Wenn ich die Prozedur mit bash wiederhole, erhalte ich mit Ihrem Beispiel eine völlig andere Ergebnismenge:
Gleicher Satz von Dateien:
Radikal unterschiedliche Ergebnisse mit Ihrem Code:
Mit einem Shell Glob funktioniert es einwandfrei:
Der Grund, warum sich Bash so verhält, geht auf einen der Punkte zurück, die ich am Anfang der Antwort angesprochen habe: "Die Datei glob entspricht möglicherweise mehr als einer Datei".
ls
gibt den gleichen glob (a?b
) für mehrere Dateien zurück, sodass wir jedes Mal, wenn wir diesen glob erweitern, jede einzelne Datei erhalten, die mit ihm übereinstimmt.So erstellen Sie die Liste der von mir verwendeten Dateien neu:
Die Hex-Code-Zeichen sind UTF-8-NBSP-Zeichen.
quelle
ls
. Ich habe Sie auch gebeten, Ihren Code zu testen, da er nicht funktioniert. Was hat zsh damit zu tun?Lassen Sie uns versuchen, ein wenig zu vereinfachen:
Sehen? Das ist schon falsch, genau dort. Es gibt 3 Dateien, aber bash meldet 4. Dies liegt daran,
set
dass dem die generierten Globs gegeben werden,ls
die von der Shell erweitert werden, bevor sie an übergeben werdenset
. Welches ist, warum Sie bekommen:Oder wenn Sie es vorziehen:
Das obige wurde weiter ausgeführt
bash 4.2.45
.quelle
ls -1qRi | grep -o '^ *[0-9]*'
der Sie diels
Ausgabe analysieren können. Das ist die schnellste und beste Methode, um eine Liste der Inode-Nummern zu erhalten.Die Ausgabe von
ls -q
ist überhaupt kein Glob. Es?
bedeutet "Es gibt hier ein Zeichen, das nicht direkt angezeigt werden kann". Globs?
bedeuten "Hier ist jedes Zeichen erlaubt".Globs haben andere Sonderzeichen (
*
und[]
zumindest und innerhalb des[]
Paares gibt es mehr). Keiner von denen wird von entkommenls -q
.Wenn Sie die
ls -1q
Ausgabe behandeln, gibt es eine Reihe von Globs und erweitern Sie sie. Sie erhalten nicht nur dasx
Doppelte, Sie werden es auch[x]
komplett vermissen . Als Glob passt es sich nicht als String an.ls -q
soll deine Augen und / oder das Terminal vor verrückten Charakteren bewahren und nichts produzieren, was du der Shell zurückgeben kannst.quelle
Die Antwort ist einfach: Die Sonderfälle, die
ls
Sie behandeln müssen, überwiegen jeden möglichen Nutzen. Diese Sonderfälle können vermieden werden, wenn Sie diels
Ausgabe nicht analysieren .Das Mantra hier ist , dem Dateisystem des Benutzers niemals zu vertrauen (das Äquivalent, Benutzereingaben niemals zu vertrauen ). Wenn es eine Methode gibt, die mit 100% iger Sicherheit immer funktioniert, sollte es die Methode sein, die Sie bevorzugen, auch wenn Sie
ls
dasselbe tut, aber mit weniger Sicherheit. Ich werde nicht auf technische Details eingehen, da diese von Terdon und Patrick ausführlich behandelt wurden. Ich weiß, dass ich aufgrund des Risikos,ls
in einer wichtigen (und möglicherweise teuren) Transaktion, in der mein Job / Prestige auf dem Spiel steht, eine Lösung vorziehen werde, die keine gewisse Unsicherheit aufweist, wenn sie vermieden werden kann.Ich weiß, einige Leute bevorzugen ein gewisses Risiko gegenüber der Gewissheit , aber ich habe einen Fehlerbericht eingereicht .
quelle
Der Grund, warum Leute sagen, niemals etwas zu tun, ist nicht notwendigerweise, weil es absolut positiv nicht richtig gemacht werden kann. Wir sind möglicherweise in der Lage, dies zu tun, aber es kann sowohl räumlich als auch zeitlich komplizierter und weniger effizient sein. Zum Beispiel wäre es völlig in Ordnung zu sagen, dass Sie in x86-Assembly niemals ein großes E-Commerce-Backend erstellen sollten.
Nun zum vorliegenden Problem: Wie Sie gezeigt haben, können Sie eine Lösung erstellen, die ls analysiert und das richtige Ergebnis liefert - Richtigkeit ist also kein Problem.
Ist es komplizierter? Ja, aber das können wir hinter einer Hilfsfunktion verbergen.
Nun zur Effizienz:
Platzsparend: Ihre Lösung ist darauf angewiesen
uniq
, Duplikate herauszufiltern. Daher können wir die Ergebnisse nicht träge generieren. Also entwederO(1)
vs.O(n)
oder beides habenO(n)
.Zeiteffizienz: Im besten Fall
uniq
wird ein Hashmap-Ansatz verwendet, sodass wir immer noch einenO(n)
Algorithmus für die Anzahl der beschafften Elemente haben , obwohl dies wahrscheinlich der Fall istO(n log n)
.Jetzt das eigentliche Problem: Während Ihr Algorithmus immer noch nicht so schlecht aussieht, habe ich wirklich darauf geachtet, beschaffte Elemente und keine Elemente für n zu verwenden. Weil das einen großen Unterschied macht. Angenommen, Sie haben eine Datei
\n\n
, die einen Glob ergibt,??
sodass alle 2 Zeichendateien in der Auflistung übereinstimmen. Lustigerweise, wenn Sie eine andere Datei haben\n\r
, die ebenfalls??
alle 2-Zeichen-Dateien ergibt und auch zurückgibt . Sehen Sie, wohin das führt? Exponentielles statt lineares Verhalten wird mit Sicherheit als "schlechteres Laufzeitverhalten" bezeichnet. Dies ist der Unterschied zwischen einem praktischen Algorithmus und einem Algorithmus, über den Sie in theoretischen CS-Fachzeitschriften schreiben.Jeder liebt Beispiele, oder? Auf geht's. Erstellen Sie einen Ordner mit dem Namen "test" und verwenden Sie dieses Python-Skript in demselben Verzeichnis, in dem sich der Ordner befindet.
Das einzige, was dies bewirkt, ist, alle Produkte der Länge 3 für 7 Zeichen zu generieren. Die Mathematik der High School sagt uns, dass es 343 Dateien sein sollten. Nun, das sollte wirklich schnell zu drucken sein, also schauen wir mal:
Jetzt lass uns deine erste Lösung ausprobieren, weil ich das wirklich nicht verstehe
was hier auf Linux Mint 16 zu arbeiten (was meiner Meinung nach Bände für die Benutzerfreundlichkeit dieser Methode spricht).
Auf jeden Fall sollte die frühere Lösung mindestens so schnell sein wie die spätere (keine Inode-Tricks in dieser - aber diese sind unzuverlässig, sodass Sie die Richtigkeit aufgeben würden), da das oben genannte Ergebnis so gut wie nur gefiltert wird.
Also, wie lange noch?
nehmen? Nun, ich weiß es wirklich nicht, es dauert eine Weile, bis ich die 343 ^ 343-Dateinamen überprüft habe - ich werde es Ihnen nach dem heißen Tod des Universums sagen.
quelle
Die erklärte Absicht des OP wurde angesprochen
Vorwort und Begründung der ursprünglichen Antwort † aktualisiert am 18.05.2015
mikeserv (der OP) erklärte im letzten Update zu seiner Frage: "Ich finde es schade, dass ich diese Frage zum ersten Mal gestellt habe, um auf eine Quelle von Fehlinformationen hinzuweisen. "
Na gut; Ich finde es ziemlich schade, dass ich so viel Zeit damit verbracht habe, herauszufinden , wie ich meine Bedeutung erklären kann, um das herauszufinden , während ich die Frage erneut las. Diese Frage endete „[Erzeugen] Diskussion eher als Antworten“ ‡ und endete bei einem Gewicht von ~ 18K von Text (für die Frage allein, um nur klar zu sein) , die lange auch nur für eine Blog - Post wären.
Aber StackExchange ist nicht Ihre Seifenkiste und auch nicht Ihr Blog. Tatsächlich haben Sie es jedoch als mindestens einen Teil von beiden verwendet. Die Leute haben viel Zeit damit verbracht, Ihr "To-Point-Out" zu beantworten, anstatt die eigentlichen Fragen der Leute zu beantworten. An dieser Stelle werde ich die Frage als nicht passend für unser Format kennzeichnen, da das OP ausdrücklich erklärt hat, dass es überhaupt nicht beabsichtigt war, eine Frage zu sein.
An diesem Punkt bin ich nicht sicher, ob meine Antwort auf den Punkt war oder nicht; wahrscheinlich nicht, aber es war auf einige Ihrer Fragen gerichtet, und vielleicht kann es eine nützliche Antwort für jemand anderen sein; Anfänger haben Mut, einige dieser "nicht" verwandeln sich in "manchmal", wenn Sie mehr Erfahrung haben. :)
Generell...
bitte verzeihen Sie verbleibende Ecken und Kanten; Ich habe schon viel zu viel Zeit damit verbracht ... anstatt das OP direkt zu zitieren (wie ursprünglich beabsichtigt), werde ich versuchen, es zusammenzufassen und zu paraphrasieren.
[weitgehend überarbeitet von meiner ursprünglichen Antwort] Nach Prüfung glaube ich, dass ich die Betonung, die das OP auf die von mir beantworteten Fragen legte
, falsch gelesen habe; Die angesprochenen Punkte wurden jedoch angesprochen , und ich habe die Antworten größtenteils unangetastet gelassen, da ich glaube, dass sie auf den Punkt gebracht sind und Probleme ansprechen, die ich auch in anderen Zusammenhängen in Bezug auf Ratschläge für Anfänger angesprochen habe.
In dem ursprünglichen Beitrag wurde auf verschiedene Weise gefragt, warum verschiedene Artikel Ratschläge gaben, z. B. "Keine
ls
Ausgabe analysieren " oder "Sie sollten keinels
Ausgabe analysieren" .Mein Lösungsvorschlag für dieses Problem lautet, dass Beispiele für solche Aussagen lediglich Beispiele für ein leicht anders formuliertes Idiom sind, bei dem ein absoluter Quantifikator mit einem Imperativ gepaart wird [z. B. «nicht [je] X», «[Du solltest] immer Y», «[man sollte] nie Z»], um Aussagen zu bilden, die als allgemeine Regeln oder Richtlinien verwendet werden sollen, insbesondere wenn sie denjenigen gegeben werden, die neu in einem Fach sind, anstatt als absolute Wahrheiten gedacht zu sein ungeachtet der offensichtlichen Form dieser Aussagen.
Wenn Sie anfangen, neue Themen zu erlernen, und wenn Sie nicht genau wissen, warum Sie etwas anderes tun müssen, ist es eine gute Idee, einfach die anerkannten allgemeinen Regeln ausnahmslos zu befolgen - es sei denn, Sie werden von einer erfahrenen Person angeleitet das selbst. Mit zunehmender Kompetenz und Erfahrung können Sie außerdem feststellen, wann und ob in einer bestimmten Situation eine Regel gilt. Sobald Sie ein signifikantes Erfahrungsniveau erreicht haben, werden Sie wahrscheinlich zuerst die Gründe für die allgemeine Regel verstehen, und an diesem Punkt können Sie beginnen, Ihr Urteil darüber zu fällen, ob und auf welcher Ebene die Gründe für die Regel zutreffen diese Situation, und auch, ob es vielleicht übergeordnete Bedenken gibt.
Und dann könnte sich ein Experte vielleicht dafür entscheiden, Dinge zu tun, die gegen "The Rules" verstoßen. Aber das würde sie nicht weniger zu "The Rules" machen.
Und damit zum vorliegenden Thema: Meiner Ansicht nach sehe ich, nur weil ein Experte in der Lage sein könnte, gegen diese Regel zu verstoßen, ohne völlig niedergeschlagen zu werden, keine Möglichkeit, einem Anfänger zu rechtfertigen, dass dies "manchmal" der Fall ist okay, um die
ls
Ausgabe zu analysieren , weil: es ist nicht . Zumindest ist es für Anfänger nicht richtig, dies zu tun.Sie legen Ihre Bauern immer in die Mitte; in der Eröffnung ein Stück, ein Zug; Schloss zum frühestmöglichen Zeitpunkt; Ritter vor Bischöfen; ein ritter am rand ist grimmig; und stellen Sie immer sicher, dass Sie Ihre Berechnung bis zum Ende durchschauen können! (Hoppla, tut mir leid, ich werde müde, das ist für den Schach-StackExchange.)
Regeln, die gebrochen werden sollen?
Wenn Sie einen Artikel zu einem Thema lesen, das sich an Anfänger richtet oder wahrscheinlich von diesen gelesen wird, werden Sie häufig Folgendes sehen:
Zwar scheinen diese Aussagen absolut und zeitlos zu sein, aber sie sind es nicht. Stattdessen ist dies eine Möglichkeit, allgemeine Regeln (aka "Richtlinien", "Faustregeln", "Grundlagen" usw.) aufzustellen, die zumindest für die Anfänger, die diese Artikel lesen, eine geeignete Möglichkeit darstellen. Nur weil sie als absolut angegeben sind, binden die Regeln Fachleute und Experten nicht [die wahrscheinlich diejenigen waren, die diese Regeln überhaupt erst zusammengefasst haben, um die im Laufe der Wiederholung gewonnenen Erkenntnisse aufzuzeichnen und weiterzugeben Probleme in ihrem speziellen Handwerk.]
Diese Regeln werden sicherlich nicht verraten, wie ein Experte mit einem komplexen oder nuancierten Problem umgehen würde, bei dem diese Regeln beispielsweise im Widerspruch zueinander stehen. oder bei denen die Bedenken, die überhaupt zur Regel geführt haben, einfach nicht zutreffen. Experten haben keine Angst davor (oder sollten keine Angst davor haben!), Einfach Regeln zu brechen, von denen sie zufällig wissen, dass sie in einer bestimmten Situation keinen Sinn ergeben. Experten haben ständig damit zu tun, verschiedene Risiken und Bedenken in ihrem Handwerk auszugleichen, und müssen häufig ihr Urteilsvermögen einsetzen, um diese Art von Regeln zu brechen. Sie müssen verschiedene Faktoren ausbalancieren und dürfen sich nicht nur auf eine Tabelle mit zu befolgenden Regeln verlassen. Nehmen Sie
Goto
als Beispiel: Es gab eine lange, wiederkehrende Debatte darüber, ob sie schädlich sind. (Ja, nicht immer gotos verwenden;. D)Ein modaler Vorschlag
Ein merkwürdiges Merkmal, zumindest auf Englisch, und ich stelle mir in vielen anderen Sprachen allgemeine Regeln vor, ist, dass sie in der gleichen Form wie ein Modalvorschlag angegeben sind, die Experten auf einem Gebiet jedoch bereit sind, eine allgemeine Regel für a anzugeben Situation, die ganze Zeit zu wissen, dass sie die Regel brechen, wenn dies angebracht ist. Es ist daher klar, dass diese Anweisungen nicht den gleichen Anweisungen in der modalen Logik entsprechen sollen.
Deshalb sage ich, dass sie einfach idiomatisch sein müssen. Anstatt wirklich eine "nie" - oder "immer" -Situation zu sein, dienen diese Regeln in der Regel dazu, allgemeine Richtlinien zu kodifizieren, die für eine Vielzahl von Situationen geeignet sind und die, wenn Anfänger sie blind befolgen, wahrscheinlich weitreichende Folgen haben bessere Ergebnisse als der Anfänger, der sich ohne guten Grund gegen sie entscheidet. Manchmal kodifizieren sie Regeln, was einfach zu minderwertigen Ergebnissen führt und nicht zu den völligen Fehlern, die mit falschen Entscheidungen einhergehen, wenn sie gegen die Regeln verstoßen.
Allgemeine Regeln sind also nicht die absoluten Modalsätze, die sie an der Oberfläche zu sein scheinen, sondern eine Kurzform, um die Regel mit einem implizierten Standard-Boilerplate zu beschreiben, etwa wie folgt:
Wobei Sie natürlich
ls
anstelle von $ {RULE} "Niemals die Ausgabe analysieren " ersetzen könnten . :)Oh ja! Was über Parsing
ls
Output?Nun, angesichts all dessen ... ich denke, es ist ziemlich klar, dass diese Regel eine gute ist. Zunächst muss die reale Regel als idiomatisch verstanden werden, wie oben erläutert ...
Darüber hinaus muss man nicht nur sehr gut mit Shell-Skripten umgehen können, um zu wissen, ob sie in bestimmten Fällen fehlerhaft sein können. Es ist auch wichtig, dass man genau so gut weiß, dass man etwas falsch gemacht hat, wenn man versucht, es beim Testen zu brechen! Und ich sage zuversichtlich, dass eine sehr große Mehrheit des wahrscheinlichen Publikums solcher Artikel (mit Ratschlägen wie „Analysieren Sie nicht die Ausgabe von
ls
!“) Diese Dinge nicht kann , und diejenigen, die über solche Fähigkeiten verfügen, werden dies wahrscheinlich erkennen sie finden es selbst heraus und ignorieren die Regel trotzdem.Aber ... sehen Sie sich diese Frage an und wie selbst Leute, die wahrscheinlich die Fähigkeit haben, es für einen schlechten Ruf hielten, dies zu tun; und wie viel Mühe der Verfasser der Frage aufgewendet hat, um an einen Punkt des aktuell besten Beispiels zu gelangen! Ich garantiere Ihnen, dass bei einem so schweren Problem 99% der Leute da draußen falsch liegen und möglicherweise sehr schlechte Ergebnisse erzielen! Auch wenn sich die Methode als gut herausstellt; Bis eine (oder eine andere)
ls
Analyseidee von den IT- / Entwicklerleuten als Ganzes übernommen wird, viele Tests (insbesondere Zeittests) übersteht und es schließlich schafft, den Status einer "gemeinsamen Technik" zu erreichen, ist es wahrscheinlich, dass a Viele Leute könnten es versuchen und es falsch machen ... mit katastrophalen Folgen.So werde ich ein letztes Mal wiederholen .... dass, besonders in diesem Fall , dass deshalb „ nie analysieren
ls
Ausgang!“ ist definitiv der richtige Weg, um es auszudrücken.[UPDATE 2014-05-18: Begründung für die Beantwortung (oben) geklärt, um auf einen Kommentar von OP zu antworten; Der folgende Zusatz ist eine Antwort auf die Ergänzungen des OP zu der Frage von gestern.]
[UPDATE 2014-11-10: Header hinzugefügt und Inhalte neu organisiert / überarbeitet; und auch: Neuformatierung, Neuformulierung, Klärung und ähm ... "prägnantes" ... ich wollte, dass dies einfach eine Bereinigung ist, obwohl es sich in eine Art Überarbeitung verwandelt hat. Ich hatte es in einem traurigen Zustand hinterlassen, also habe ich hauptsächlich versucht, ihm einen Auftrag zu erteilen. Ich fand es wichtig, den ersten Abschnitt weitgehend intakt zu lassen. also nur zwei kleinere Änderungen, überflüssig "aber" entfernt und "das" hervorgehoben.]
† Ich beabsichtigte dies ursprünglich nur als Klarstellung meines Originals; aber entschied sich für andere Ergänzungen nach Überlegung
‡ Richtlinien zu Beiträgen finden Sie unter https://unix.stackexchange.com/tour
quelle
ls
!' Richtige Ratschläge: 1. Zeigen Sie (zu Ihrer Zufriedenheit), dass für jeden Anwendungsfall, in dem einels
Ausgabe analysiert werden kann, eine andere Lösung verfügbar ist, die in gewisser Weise überlegen ist, ohne dies zu tun. 2. zeigen Sie, dass die Aussage in den genannten Fällen keine wörtliche ist.ls
ist ein Computerprogramm - Sie können ComputerausgabenIst es möglich, die Ausgabe von
ls
in bestimmten Fällen zu analysieren ? Sicher. Die Idee, eine Liste von Inode-Nummern aus einem Verzeichnis zu extrahieren, ist ein gutes Beispiel - wenn Sie wissen, dass die Implementierung diesls
unterstützt-q
und daher jede Datei genau eine Ausgabezeile erzeugt und Sie nur die Inode-Nummern benötigen, aus denen sie analysiert werdenls -Rai1q
Ausgabe ist sicherlich eine mögliche Lösung. Hätte der Autor zuvor keinen Rat wie "Niemals die Ausgabe von ls analysieren" gesehen, würde er wahrscheinlich nicht über Dateinamen mit Zeilenumbrüchen nachdenken und wahrscheinlich das "q" als Ergebnis und das "ls" weglassen Code würde in diesem Edge-Fall auf subtile Weise beschädigt - selbst in Fällen, in denenls
die Ausgabe des Parsings sinnvoll ist, ist dieser Ratschlag dennoch nützlich.Der umfassendere Punkt ist, dass, wenn ein Neuling in der Shell-Skripterstellung versucht, ein Skript herauszufinden (zum Beispiel), was die größte Datei in einem Verzeichnis ist oder was die zuletzt geänderte Datei in einem Verzeichnis ist, sein erster Instinkt darin besteht
ls
, s zu analysieren output - verständlich, weills
es eines der ersten Kommandos ist, das ein Neuling lernt.Leider ist dieser Instinkt falsch und dieser Ansatz ist gebrochen. Noch bedauerlicher ist, dass es auf subtile Weise kaputt ist - es wird die meiste Zeit funktionieren, aber in Randfällen, die möglicherweise von jemandem mit Kenntnissen des Codes ausgenutzt werden könnten, scheitern.
Der Neuling könnte sich
ls -s | sort -n | tail -n 1 | awk '{print $2}'
eine Möglichkeit vorstellen, die größte Datei in einem Verzeichnis abzurufen. Und es funktioniert, bis Sie eine Datei mit einem Leerzeichen im Namen haben.OK, wie wäre es
ls -s | sort -n | tail -n 1 | sed 's/[^ ]* *[0-9]* *//'
? Funktioniert einwandfrei, bis Sie eine Datei mit einer neuen Zeile im Namen haben.Hilft das Hinzufügen
-q
vonls
Argumenten zu, wenn der Dateiname eine neue Zeile enthält? Möglicherweise sieht es so aus, bis Sie zwei verschiedene Dateien haben, die ein nicht druckbares Zeichen an derselben Stelle im Dateinamen enthalten. In derls
Ausgabe können Sie dann nicht unterscheiden, welche der Dateien die größten waren. Schlimmer noch, um das "?" Zu erweitern, greift er wahrscheinlich auf seine Shell zurückeval
- was zu Problemen führt, wenn er eine Datei mit dem Namen "?"Hilft das
--quoting-style=shell
(wenn Ihr esls
überhaupt unterstützt)? Nein, zeigt noch? Bei nicht druckbaren Zeichen ist es also immer noch nicht eindeutig, welche der mehreren Übereinstimmungen die größte war.--quoting-style=literal
? Nein, das gleiche.--quoting-style=locale
oder--quoting-style=c
könnte helfen, wenn Sie nur den Namen der größten Datei eindeutig drucken müssen, aber wahrscheinlich nicht, wenn Sie danach etwas mit der Datei tun müssen - es wäre ein Haufen Code, um das Anführungszeichen rückgängig zu machen und zum wirklichen Dateinamen zurückzukehren dass Sie es weitergeben können, sagen wir, gzip.Und am Ende all dieser Arbeiten, auch wenn das, was er hat, sicher und korrekt für alle möglichen Dateinamen ist, ist es unlesbar und nicht mehr zu pflegen und hätte viel einfacher, sicherer und lesbarer in Python oder Perl oder Ruby gemacht werden können.
Oder sogar mit anderen Shell-Werkzeugen - von oben nach unten, ich denke, das sollte den Trick machen:
Und sollte mindestens so tragbar sein, wie es
--quoting-style
ist.quelle