Warum funktioniert Ihre Funktion nicht?
Dafür gibt es wenige Gründe:
- Ich schätze,
echo
ein Artefakt wird zum Testen der Syntax verwendet. Es macht keinen Sinn, wenn Sie möchten, dass die Funktion das tut, was Sie beschrieben haben. - Versalien
HEAD
. In Linux sollte es seinhead
. Ich bin mir nicht sicher über andere OS-es, wo Sie ausführen können,bash
undhead
.HEAD
kann oder kann nicht in einigen von ihnen arbeiten,head
sollte aber überall funktionieren. - Parsing
ls
wird nicht empfohlen. Es gibt einen Artikel darüber . Der Hauptpunkt in Ihrem Fall ist, dassls
Namen mit Sonderzeichen oder nicht druckbaren Zeichen nicht zuverlässig gedruckt werden können. - Es gibt keine Logik, um nur Verzeichnisse zu testen. Möglicherweise versuchen Sie
cd
, eine Datei zu suchen, wenn kein Verzeichnis vorhanden ist. - Es gibt keine Logik, um die Situation zu handhaben, wenn das aktuelle Arbeitsverzeichnis leer ist.
Alle diese Probleme können mit Ausnahme dieser Parsing- ls
Sache debuggt werden . Es ist ein Designfehler. Wenn Sie glauben, dass ls
Einschränkungen Sie nicht beissen, können Sie eine Lösung aus dieser anderen Antwort wählen .
Um einige Tests durchzuführen, können Sie ein problematisches Verzeichnis mit erstellen mkdir "$(echo -ne "foo\nbar")"
; ls
-basierte Lösungen werden wahrscheinlich fehlschlagen, wenn dies das Verzeichnis cdrc
sollte cd
. So entfernen Sie das problematische Verzeichnis rmdir "$(echo -ne "foo\nbar")"
.
Ich habe es geschafft, eine sicherere Funktion zu schaffen.
Lösung
function cdrc { cd "$(find -maxdepth 1 -mindepth 1 -type d -exec stat --printf "%Y %n\0" {} + | sort -znr | head -zn 1 | cut -f 2- -d " ")" ;}
Erläuterung
Um meine Funktion zu erklären, werde ich sie klarer schreiben. Beachten Sie a \
am Ende einer Zeile, dass bash
der Befehl in der nächsten Zeile fortgesetzt wird. daher wird mein Code wie ein Einzeiler behandelt, er kann als Ganzes in interaktiv eingefügt werden bash
.
function cdrc { \ cd "$( \ find -maxdepth 1 -mindepth 1 -type d -exec \ stat --printf "%Y %n\0" {} + | sort -znr | head -zn 1 | cut -f 2- -d " " \ )" \ ;}
Das Verfahren ist wie folgt:
- Zunächst
find
wird ausgeführt. Es geht nicht in die Unterverzeichnisse (-maxdepth 1
), es findet auch nicht das aktuelle Verzeichnis (-mindepth 1
). Es findet nur Verzeichnisse (-type d
). Dann wird derstat
Befehl ausgeführt (Danke an-exec
):stat
Gibt die Zeit der letzten Datenänderung (%Y
, mtime, Sekunden seit Epoche), ein Leerzeichen und den Namen (%n
) aus. Aufgrund der--printf
Option wird das Zeilenvorschubzeichen nicht hinzugefügt, sondern\0
als Nullzeichen interpretiert, das am Ende jeder Zeile eingefügt werden sollte.{}
ist ein Teil derfind -exec
Syntax. Während derfind
Ausführung wird es durch den Verzeichnisnamen ersetzt, sostat
dass das Ziel bekannt ist.+
ist auch ein Teil derfind -exec
Syntax. Es bewirktfind
, dass mehrere Namen an Single übergeben werdenstat
(undstat
damit umgehen können). Auf diese Weise werden wenigerstat
Prozesse erstellt, das ist schneller.
In diesem Moment haben wir keine oder mehr Zeilen. Sie sehen ähnlich aus:
1493488341 directory name 1497365306 troublesome?directory name
Sie sind jedoch nullterminiert, selbst wenn Namen mit lästigen Zeichen vorhanden sind, werden sie ordnungsgemäß behandelt. In der ersten Spalte gibt es mtimes ohne führende Leerzeichen (ich habe das stat
Verhalten mit Nummern verschiedener Länge geprüft, um sicherzugehen, dass sich das erste Leerzeichen von mtime und dem Verzeichnisnamen unterscheidet.
- Diese Ausgabe wird weiter verarbeitet:
sort
sortiert Zeilen nach numerischem Wert (-n
), verwendet umgekehrte Reihenfolge (-r
) und arbeitet mit nullterminierten Zeichenfolgen (-z
). Auf diese Weise steht das Verzeichnis, das wir brauchen, jetzt in der ersten Zeile.- Dann
head
bleibt nur die erste Zeile (-n 1
); Es wird auch empfohlen, mit nullterminierten Strings (-z
) zu arbeiten. cut
schneidet die Linie, behandelt den Raum als Trennzeichen (-d " "
) und verlässt das zweite Feld und alles, was folgt (-f 2-
), dh alles nach dem ersten Raum Es funktioniert mit nullterminierten Strings (-z
). Die endgültige Ausgabe ist der gewünschte Verzeichnisname.
Beachten Sie, dass die Ausgabe leer ist, wenn sich im aktuellen Arbeitsverzeichnis kein Verzeichnis befindet.
$(…)
wird ersetzt durch die Ausgabe von allem, was sich darin befindet. In diesem Moment haben wir entwedercd "some directory name"
odercd ""
. Der vorherige Befehl macht, was Sie wollen. Letzteres (wenn es kein Verzeichnis gibt) tut nichts.
Die Funktion schlägt fehl, wenn das Verzeichnis, in dem es sich befinden soll, cd
verschoben oder umbenannt wird, nachdem find
es gefunden wurde. Auch stat
können Fehler (n) aus, wenn ein beliebiges Verzeichnis ist (wieder) verschoben / umbenannt, wenn die Funktion arbeitet.