Beachten Sie auch, dass ich Anführungszeichen hinzugefügt habe $MY_DIR. Auf diese Weise schlägt der Befehl nicht fehl, wenn er $MY_DIRLeerzeichen enthält.
Wenn Sie eine moderne Shell wie Bash verwenden, sollten Sie $( )anstelle von Backticks eine Capture-Shell verwenden. Sie sollten auch überlegen, den Stil Ihrer Variablen zu ändern. Sie sollten generell vermeiden, Variablennamen in Großbuchstaben in Skripten zu verwenden. Dieser Stil ist im Allgemeinen reservierten Variablen und Umgebungsvariablen vorbehalten.
input_file=$(ls -rt "$my_dir"/FILE.*.xml 2>/dev/null | head -1| xargs -r basename)
Ist das nicht ein Problem, wenn es keine Dateien gibt?
Mel Boyce
Eigentlich: ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basenamefunktioniert.
Mel Boyce
@ MelBoyce: Ich habe das zu meiner Antwort hinzugefügt. Vielen Dank.
ls ist ein Tool zum interaktiven Anzeigen von Dateiinformationen. Die Ausgabe ist für Menschen formatiert und führt zu Fehlern in Skripten. Verwenden Sie stattdessen Globs oder Find. Verstehen , warum: mywiki.wooledge.org/ParsingLs
cinelli
@cinelli: Das stimmt. Ich habe nur die Frage beantwortet.
9
In einer Pipeline werden alle Befehle gleichzeitig gestartet und nicht nacheinander ausgeführt. Sie müssen die Ausgabe also irgendwo speichern.
if ls_output=$(ls -rtd --"$MY_DIR"/FILE.*.xml);then
first_file=$(printf '%s\n'"$ls_output"| head -n 1)
first_file_name=$(basename --"$first_file")fi
Beachten Sie, dass Dateinamen keine Zeilenumbrüche enthalten. Die Verwendung von xargswürde auch Probleme mit Leerzeichen, einfachen und doppelten Anführungszeichen und Backslashes bedeuten. Wenn Variablen nicht in Anführungszeichen gesetzt werden, treten Probleme mit Leerzeichen, Tabulatoren und Platzhalterzeichen auf. Vergessen --würde Probleme mit Dateinamen bedeuten, die mit beginnen -.
So erhalten Sie den Basisnamen der ältesten Datei zshohne eine dieser Zeichenbeschränkungen (umgeht auch das Problem der begrenzten Größe von Argumenten für einen Befehl):
first_file_name=($MY_DIR/FILE.*.xml(Om[1]:t))
Wenn es keine Übereinstimmung gibt, schlägt dieser Befehl fehl und bricht das Skript ab. Sie können auch:
first_file_name=($MY_DIR/FILE.*.xml(NOm[1]:t))
In diesem Fall enthält das first_file_nameArray 1 Element, wenn eine Übereinstimmung vorliegt, oder 0, wenn nicht. Sie können dann Folgendes tun:
if(($#first_file_name)); then
printf 'Match: %s\n' $first_file_name
else
echo >&2No match
fi
So verwenden Sie dies ordnungsgemäß, um den Zweck Ihrer Anfrage zu erfüllen:
check_dir=/path/to/check
check_ext=.xml
if in_file=$(latest "$check_dir""$check_ext");then
base_fn=${in_file##*/} base_fn=${base_fn%.*}else
printf '%s\n'"No file found in $check_dir">&2fi
BEARBEITEN: Bei der Überprüfung der Frage habe ich festgestellt, dass der lsbetreffende Befehl nach der ältesten Datei in einem Verzeichnis sucht . Dieselbe Funktion könnte in umbenannt werden oldestund muss [[ $file -ot $oldest ]] && oldest=$filestattdessen den gleichen Effekt erzielen. Wir entschuldigen uns für etwaige Verwirrung.
Das Wichtigste ist, dass Sie auf keinen Fall die Ausgabe von ls analysieren sollten. noch nie.
Beachten Sie, dass im Gegensatz zu den auf ls-basierten Ansätzen bei Symlinks die Änderungszeit des Ziels der Symlinks berücksichtigt wird (fügen Sie die -LOption hinzu ls, um dasselbe Verhalten dort zu erzielen).
Anstatt den Vergleich $?gegen 0, können Sie dies tun: if ls -rf $MY_DIR/FILE.*.xml ; then.
Außerdem können Sie die Ausgabe des ersten Befehls an umleiten /dev/null. ls -rf $MY_DIR/FILE.*.xml &> /dev/null. Auf diese Weise wird dem Benutzer die zusätzliche Ausgabe nicht angezeigt.
ls
wird nicht scheitern.Antworten:
Versuche dies:
Wenn Sie
xargs
das-r
Flag übergeben, wird es nur ausgeführt,basename
wenn mindestens ein Element aus der Standardeingabe (head -1
) gelesen wird .head -1
wird ausgeführt, aber Sie werden keine Ausgabe davon sehen oder erfassen.Wenn Sie nicht möchten, dass der Benutzer eine Fehlerausgabe von
ls
sieht, können Sie denls
stderr-Stream an umleiten/dev/null
.Beachten Sie auch, dass ich Anführungszeichen hinzugefügt habe
$MY_DIR
. Auf diese Weise schlägt der Befehl nicht fehl, wenn er$MY_DIR
Leerzeichen enthält.Wenn Sie eine moderne Shell wie Bash verwenden, sollten Sie
$( )
anstelle von Backticks eine Capture-Shell verwenden. Sie sollten auch überlegen, den Stil Ihrer Variablen zu ändern. Sie sollten generell vermeiden, Variablennamen in Großbuchstaben in Skripten zu verwenden. Dieser Stil ist im Allgemeinen reservierten Variablen und Umgebungsvariablen vorbehalten.quelle
ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basename
funktioniert.In einer Pipeline werden alle Befehle gleichzeitig gestartet und nicht nacheinander ausgeführt. Sie müssen die Ausgabe also irgendwo speichern.
Beachten Sie, dass Dateinamen keine Zeilenumbrüche enthalten. Die Verwendung von
xargs
würde auch Probleme mit Leerzeichen, einfachen und doppelten Anführungszeichen und Backslashes bedeuten. Wenn Variablen nicht in Anführungszeichen gesetzt werden, treten Probleme mit Leerzeichen, Tabulatoren und Platzhalterzeichen auf. Vergessen--
würde Probleme mit Dateinamen bedeuten, die mit beginnen-
.So erhalten Sie den Basisnamen der ältesten Datei
zsh
ohne eine dieser Zeichenbeschränkungen (umgeht auch das Problem der begrenzten Größe von Argumenten für einen Befehl):Wenn es keine Übereinstimmung gibt, schlägt dieser Befehl fehl und bricht das Skript ab. Sie können auch:
In diesem Fall enthält das
first_file_name
Array 1 Element, wenn eine Übereinstimmung vorliegt, oder 0, wenn nicht. Sie können dann Folgendes tun:quelle
Suchen Sie die zuletzt geänderte Datei in einem Verzeichnis:
Verwendung:
latest [directory/path/ [.extension]]
basename
Verwenden Sie die Parametererweiterung, anstatt zu rufen .In einem Verzeichnis mit diesen Inhalten:
Der Inhalt der Variable base_fn wäre:
newest
So verwenden Sie dies ordnungsgemäß, um den Zweck Ihrer Anfrage zu erfüllen:
BEARBEITEN: Bei der Überprüfung der Frage habe ich festgestellt, dass der
ls
betreffende Befehl nach der ältesten Datei in einem Verzeichnis sucht . Dieselbe Funktion könnte in umbenannt werdenoldest
und muss[[ $file -ot $oldest ]] && oldest=$file
stattdessen den gleichen Effekt erzielen. Wir entschuldigen uns für etwaige Verwirrung.Das Wichtigste ist, dass Sie auf keinen Fall die Ausgabe von ls analysieren sollten. noch nie.
quelle
ls
-basierten Ansätzen bei Symlinks die Änderungszeit des Ziels der Symlinks berücksichtigt wird (fügen Sie die-L
Option hinzuls
, um dasselbe Verhalten dort zu erzielen).Ich denke, dass die beste Option hier ist:
Wenn es keine Datei gibt, ist der Rückgabecode von ls 2, wenn jedoch eine Datei gefunden wird, ist er 0.
quelle
$?
gegen0
, können Sie dies tun:if ls -rf $MY_DIR/FILE.*.xml ; then
./dev/null
.ls -rf $MY_DIR/FILE.*.xml &> /dev/null
. Auf diese Weise wird dem Benutzer die zusätzliche Ausgabe nicht angezeigt.