INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`
Ich wollte den zweiten Befehl ( head -1
) nur ausführen, wenn der erste Befehl erfolgreich ist. Wie verbessere ich diesen Befehl?
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`
Ich wollte den zweiten Befehl ( head -1
) nur ausführen, wenn der erste Befehl erfolgreich ist. Wie verbessere ich diesen Befehl?
Antworten:
Versuche dies:
INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml | head -1 | xargs -r basename`
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 den ls
stderr-Stream an umleiten /dev/null
.
INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename`
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.
input_file=$(ls -rt "$my_dir"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename)
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.
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 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):
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_name
Array 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 >&2 No match
fi
Suchen Sie die zuletzt geänderte Datei in einem Verzeichnis:
latest() {
local file path=${1:-.} ext=${2-} latest
for file in "${path%/}"/*"$ext"; do
[[ $file -nt $latest ]] && latest=$file
done
[[ $latest ]] && printf '%s\n' "$latest"
}
Verwendung: latest [directory/path/ [.extension]]
basename
Verwenden Sie die Parametererweiterung, anstatt zu rufen .
in_file=$(latest in/my/dir .xml)
base_fn=${in_file##*/} base_fn=${base_fn%.*}
In einem Verzeichnis mit diesen Inhalten:
foo.xml bar.xml baz.xml newest.xml
Der Inhalt der Variable base_fn wäre: newest
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" >&2
fi
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 werden oldest
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.
ls
-basierten Ansätzen bei Symlinks die Änderungszeit des Ziels der Symlinks berücksichtigt wird (fügen Sie die -L
Option hinzu ls
, um dasselbe Verhalten dort zu erzielen).
Ich denke, dass die beste Option hier ist:
ls -rf $MY_DIR/FILE.*.xml
if [ $? -eq 0 ]; then
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml|head -1|xargs basename `
else
echo "Error!"
fi
Wenn es keine Datei gibt, ist der Rückgabecode von ls 2, wenn jedoch eine Datei gefunden wird, ist er 0.
ls
wird nicht scheitern.