Leitet die Ausgabe eines Befehls weiter, wenn dieser erfolgreich war

Leitet die Ausgabe eines Befehls weiter, wenn dieser erfolgreich war
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 kann ich diesen Befehl verbessern?

Antwort1

Versuche dies:

INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml | head -1 | xargs -r basename`

Das Übergeben xargsdes -rFlags führt dazu, dass es nur ausgeführt wird, basenamewenn mindestens ein Element von der Standardeingabe ( head -1) gelesen wird.

head -1wird ausgeführt, aber Sie sehen oder erfassen keine Ausgabe davon.

Wenn Sie nicht möchten, dass der Benutzer Fehlerausgaben von sieht ls, können Sie lsden Stderr-Stream von zu 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 $MY_DIRer Leerzeichen enthält.

Wenn Sie eine moderne Shell wie Bash verwenden, sollten Sie $( )anstelle von Backticks eine Capture-Shell verwenden. Sie sollten auch erwägen, den Stil Ihrer Variablen zu ändern. Sie sollten generell vermeiden, in Skripten ausschließlich Variablennamen in Großbuchstaben zu verwenden. Dieser Stil ist im Allgemeinen reservierten und Umgebungsvariablen vorbehalten.

input_file=$(ls -rt "$my_dir"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename)

Antwort2

In einer Pipeline werden alle Befehle gleichzeitig gestartet und ausgeführt, nicht einer nach dem anderen. 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 davon ausgegangen wird, dass Dateinamen keine Zeilenumbruchzeichen enthalten. Die Verwendung von xargswürde auch Probleme mit Leerzeichen, einfachen und doppelten Anführungszeichen und Backslashes bedeuten. Das Weglassen von Variablen ohne Anführungszeichen würde Probleme mit Leerzeichen, Tabulatoren und Platzhalterzeichen bedeuten. Das Vergessen --würde Probleme mit Dateinamen bedeuten, die mit beginnen -.

So erhalten Sie den Basisnamen der ältesten Datei zshohne diese Zeichenbeschränkungen (umgeht außerdem das Problem der begrenzten Größe der Argumente eines Befehls):

 first_file_name=($MY_DIR/FILE.*.xml(Om[1]:t))

Wenn keine Übereinstimmung gefunden wird, schlägt der Befehl fehl und das Skript wird abgebrochen. Sie können auch Folgendes tun:

 first_file_name=($MY_DIR/FILE.*.xml(NOm[1]:t))

In diesem Fall first_file_nameenthält das Array 1 Element, wenn eine Übereinstimmung vorliegt, und 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

Antwort3

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]]

Verwenden Sie anstelle des Aufrufs basenamedie Parametererweiterung.

in_file=$(latest in/my/dir .xml)
base_fn=${in_file##*/} base_fn=${base_fn%.*}

In einem Verzeichnis mit diesem Inhalt:

foo.xml bar.xml baz.xml newest.xml

Der Inhalt der Variable base_fn wäre:newest

So verwenden Sie es 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

EDIT: bei der Überprüfung der Frage habe ich festgestellt, dass der lsfragliche Befehl nach dem suchtältesteDatei in einem Verzeichnis. Diese gleiche Funktion könnte umbenannt werden in oldestund hätte [[ $file -ot $oldest ]] && oldest=$filestattdessen, um denselben Effekt zu erzielen. Entschuldigen Sie etwaige Verwirrung.

Wichtig zu beachten ist, dass Sie die Ausgabe von ls auf keinen Fall und unter keinen Umständen analysieren sollten. Niemals.

Antwort4

Ich denke, die beste Option ist hier:

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 keine Datei vorhanden ist, lautet der Rückgabecode von ls 2. Wenn jedoch eine Datei gefunden wird, lautet der Rückgabecode 0.

verwandte Informationen