Ich schreibe gerade das folgende Skript. Der Code sucht in einem bestimmten Verzeichnis nach einem vom Benutzer eingegebenen Dateinamen. Das Skript prüft zunächst, ob die Eingabedatei eine GZIP-Datei ist. Wenn ja, führt es die entsprechenden Prüfungen durch. Wenn die Datei nicht GZIP-komprimiert ist, antwortet es mit einem inkompatiblen Dateitext.
Das Problem, auf das ich stoße, ist online 7
. Unabhängig von der Dateierweiterung erhalte ich als endgültige Ausgabe eine inkompatible Datei.
#!/bin/bash
DATE=$(date +%Y-%m-%d)
L0_Report_Generator=("/home/ubuntu/$gzip_file")
echo -n "Enter File Directory:"$gzip_file
read $gzip_file
for gzip_file in {$L0_Report_Generator}; do
if [[ $gzip_file = "test_sub"*"gz" ]] #Check file extension for gzip compression
then
gunzip $gzip_file
echo "file Level 0 QC Check"
echo ${DATE}
echo "File Header"
cat $gzip_file | head
echo "Total Records"
cat $gzip_file | wc -l
echo "File Unique Records Size"
cat $L0_Report_Generator | sort -u | wc -l
rm $gzip_file
else [[ $gzip_file != "test_sub"*"gz" ]] #If file is anything other than .gz and csv - rort will not run
then
echo "incompatible file"
fi
done
Antwort1
Wenn Sie mithilfe eines Platzhalterausdrucks innerhalb einer if-Anweisung nach der Dateinamenerweiterung „.gz“ suchen möchten, verwenden Sie einen Ausdruck wie den folgenden:
if [[ "${gzip_file}" = *.gz ]]; then echo true; else echo false; fi
So können Sie es testen:
if [[ "file.gz" = *.gz ]]; then echo true; else echo false; fi
Und:
if [[ "file.txt" = *.gz ]]; then echo true; else echo false; fi
Das erste Beispiel erzeugt true
als Ausgabe und das zweite Beispiel erzeugt false
.
Schauen wir uns nun Ihren Code an. Ihre if-Anweisung enthält stattdessen den folgenden bedingten Ausdruck:
[[ $gzip_file = "test_sub"*"gz" ]]
Insbesondere schließen Sie „test_sub“ als Teilzeichenfolge in Ihr Übereinstimmungsmuster ein. Versuchen Sie, dies zu entfernen.
Antwort2
Zusätzlich zu dem, was @igal über die Überprüfung der Dateierweiterung gesagt hat: Sie haben viele Fehler in der Variablensyntax und -verwendung. Beginnen Sie mit Zeile 3:
L0_Report_Generator=("/home/ubuntu/$gzip_file")
Die Variable gzip_file
wurde noch nicht gesetzt, daher $gzip_file
wird sie durch nichts ersetzt, wenn die Shell sie erweitert. Außerdem weisen die Klammern var=(something)
ein Array statt einer einfachen Variable zu, und in diesem Fall ergibt das keinen Sinn.
Die vierte Zeile, echo -n "Enter File Directory:"$gzip_file
, hat dasselbe Problem mit der Variable gzip_file
. Sie hat außerdem das Problem, dass sie echo -n
unvorhersehbar ist und unter verschiedenen Versionen des Befehls unterschiedliche Ergebnisse liefert echo
. Um einen String ohne Zeilenvorschub zu drucken, ist es viel besser, zu verwenden printf "%s" "string to print"
, aber in diesem Fall gibt es eine bessere Option, auf die ich gleich eingehen werde.
Die fünfte Zeile, read $gzip_file
, scheint dazu gedacht zu sein, Benutzereingaben in die Variable einzulesen gzip_file
, aber das tut sie nicht. In der Shell setzt man $
vor einen Variablennamen, dassbekommtder aktuelle Wert der Variable. Hier möchten SieSatz$
es, also müssen Sie das off: weglassen read gzip_file
. Aber das würde ich nicht tun. Ich würde die Eingabeaufforderung (die Sie echo
in Zeile 4 haben) als Teil des read
Befehls einschließen:
read -p "Enter File Directory:" gzip_file
Ok, jetzt zu Zeile 6:
for gzip_file in {$L0_Report_Generator}; do
Dies scheint die Einstellunggzip_file
wieder(ersetzt den Wert, den wir gerade read
eingefügt haben). Versuchen Sie hier tatsächlich etwas festzulegen gzip_file
, und die vorherigen Variablenreferenzen hätten wirklich eine andere Variable sein sollen (vielleicht gzip_dir
stattdessen)?
Außerdem in
ergibt der Teil keinen Sinn. Ich glaube, Sie versuchen, die Variable zu verwenden L0_Report_Generator
, aber in diesem Fall sollte die öffnende Klammernachdas Dollarzeichen. Aber das macht auch nicht ganz Sinn, denn ${L0_Report_Generator}
es wird (wenn ich richtig verstehe, was das tun soll) nur der Pfad zu einem Verzeichnis sein. for ... in
iteriert nicht über den Inhalt von Verzeichnissen, sondern über eine Liste vonWörter, wie for var in word1 word2 "word 3 which has several spaces in it" word4; do
. Wenn Sie eine Liste der Dateien in einem Verzeichnis erhalten möchten, müssen Sie ein Platzhalterzeichen verwenden, wie for var in dir/*; do
-- die Shell erweitert das mit Platzhalterzeichen versehene Dateimuster in eine Liste übereinstimmender Dateien, wobei jede als Wort behandelt wird, und iteriert über sie. Sie haben auch die Möglichkeit, Übereinstimmungen auf Dateien mit einer bestimmten Erweiterung zu beschränken, indem Sie diese in das Muster aufnehmen, wie dir/*.gz
.
Drei weitere Hinweise: Ich rate davon ab, Variablennamen in Großbuchstaben wie zu verwenden DATE
, um Konflikte mit den verschiedenen Umgebungsvariablen in Großbuchstaben zu vermeiden, die für die Shell oder einige Dienstprogramme eine besondere Bedeutung haben. Setzen Sie Ihre Variablenreferenzen außerdem immer in doppelte Anführungszeichen (also „use“ "$var"
statt nur „ $var
), um unerwartete Anomalien bei der Analyse zu vermeiden. Und die else
Klausel hat keinen Test, also else [[ some test ]]
ergibt „using“ keinen Sinn (und „ then
after“ else
ist ein Syntaxfehler).
Wenn ich also richtig verstanden habe, was das Skript tun soll, würde ich empfehlen, den Anfang des Skripts durch Folgendes zu ersetzen:
#!/bin/bash
date=$(date +%Y-%m-%d) # Note lowercase variable
read -p "Enter File Directory:" gzip_dir
L0_Report_Generator="/home/ubuntu/$gzip_dir"
for gzip_file in "${L0_Report_Generator}"/*.gz; do
... Und dann (wenn Sie das obige .gz-Muster möchten) müssen Sie nicht if
prüfen, ob $gzip_file
die Erweiterung .gz vorliegt, da das Platzhaltermuster nur .gz-Dateien auflistet.
Noch eine Anmerkung:shellcheck.netist sehr hilfreich, um auf grundlegende Fehler in Shell-Skripten hinzuweisen. Vieles von dem, was ich aufgezeigt habe, fehlt, aber der Fehler then
(den ich zunächst übersehen hatte) wurde erkannt.