Für eine Aufgabe werde ich gebeten, geschickt eine Bash-Funktion zu schreiben, die die gleiche Grundfunktionalität wie die Funktion cp
(Kopie) hat. Es muss nur eine Datei in eine andere kopiert werden, sodass nicht mehrere Dateien in ein neues Verzeichnis kopiert werden.
Da ich neu in der Bash-Sprache bin, kann ich nicht verstehen, warum mein Programm nicht funktioniert. Die ursprüngliche Funktion fordert Sie auf, eine Datei zu überschreiben, wenn sie bereits vorhanden ist. Deshalb habe ich versucht, dies zu implementieren. Es schlägt fehl.
Die Datei schlägt anscheinend in mehreren Zeilen fehl, vor allem aber unter der Bedingung, dass überprüft wird, ob die zu kopierende Datei bereits vorhanden ist ( [-e "$2"]
). Trotzdem wird die Meldung angezeigt, die ausgelöst werden soll, wenn diese Bedingung erfüllt ist (Der Dateiname ...).
Könnte mir jemand beim Reparieren dieser Datei helfen und möglicherweise nützliche Einblicke in mein grundlegendes Verständnis der Sprache geben? Der Code lautet wie folgt.
#!/bin/sh
echo "file variable: $2"
if [-e file]&> /dev/null
then
echo "The file name already exists, want to overwrite? (yes/no)"
read | tr "[A-Z]" "[a-z]"
if [$REPLY -eq "yes"] ; then
rm "$2"
echo $2 > "$2"
exit 0
else
exit 1
fi
else
cat $1 | $2
exit 0
fi
[ ... ] &> /dev/null
. Die von unterstützten Tests[ ... ]
sind immer stumm. Nur bei Syntaxfehlern wird eine Ausgabe erzeugt. Wenn Sie einen solchen Test zum Schweigen bringen, graben Sie einfach Ihr eigenes Grab.cat $1 | $2
"leitet" die Ausgabe des ersten Befehls an den Befehl in Ihrer zweiten Variablen weiter. Dies ist jedoch ein Dateiname, nicht der Name eines auszuführenden Befehls.[
Befehls in Ihrem überprüfenif
.|
und Umleiten in eine Datei mit lernen>
. Dies sind grundlegende Syntaxprobleme, die in Ihrer Klasse bereits behandelt werden sollten.Antworten:
Das
cp
Dienstprogramm überschreibt die Zieldatei gerne, wenn diese Datei bereits vorhanden ist, ohne den Benutzer dazu aufzufordern.Eine Funktion, die grundlegende Funktionen implementiert
cp
, ohne sie zu verwenden,cp
wäreWenn Sie den Benutzer vor dem Überschreiben des Ziels auffordern möchten (beachten Sie, dass dies möglicherweise nicht wünschenswert ist, wenn die Funktion von einer nicht interaktiven Shell aufgerufen wird):
Die Diagnosemeldungen sollten an den Standardfehlerstrom gesendet werden. Damit mache ich
printf ... >&2
.Beachten Sie, dass wir
rm
die Zieldatei nicht wirklich benötigen, da die Umleitung sie abschneidet. Wenn wir haben wollenrm
es zuerst, dann würden Sie haben zu prüfen , ob es sich um ein Verzeichnis ist, und wenn es ist, legen Sie die Zieldatei in diesem Verzeichnis statt, sondern nur die Art und Weisecp
tun würde. Dies tut das, aber immer noch ohne expliziterm
:Möglicherweise möchten Sie auch sicherstellen, dass die Quelle tatsächlich vorhanden ist, was etwas
cp
bewirkt (cat
tut es auch, sodass es natürlich vollständig weggelassen werden kann, aber dies würde eine leere Zieldatei erstellen):Diese Funktion verwendet keine "Bashismen" und sollte in allähnlichen
sh
Schalen funktionieren .Mit etwas mehr Optimierungen zur Unterstützung mehrerer Quelldateien und einem
-i
Flag, das die interaktive Eingabeaufforderung beim Überschreiben einer vorhandenen Datei aktiviert:Ihr Code hat schlechte Abstände
if [ ... ]
(benötigen vor und nach[
und vor Speicherplatz]
). Sie sollten auch nicht versuchen, den Test umzuleiten,/dev/null
da der Test selbst keine Ausgabe hat. Der erste Test sollte außerdem den Positionsparameter verwenden$2
, nicht die Zeichenfolgefile
.Wenn Sie
case ... esac
wie ich verwenden, müssen Sie die Antwort des Benutzers mit Klein- / Großbuchstaben vermeidentr
. Inbash
, wenn Sie diese ohnehin tun wollte , war, eine billigere Art und Weise , es zu tun zu verwenden gewesen wäreREPLY="${REPLY^^}"
(für großgeschrieben) oderREPLY="${REPLY,,}"
(für Kleinschreibung).Wenn der Benutzer mit Ihrem Code "Ja" sagt, fügt die Funktion den Dateinamen der Zieldatei in die Zieldatei ein. Dies ist kein Kopieren der Quelldatei. Es sollte bis zum eigentlichen Kopierbit der Funktion durchfallen.
Das Kopierbit haben Sie mithilfe einer Pipeline implementiert. Eine Pipeline wird verwendet, um Daten von der Ausgabe eines Befehls an die Eingabe eines anderen Befehls zu übergeben. Das müssen wir hier nicht tun. Rufen Sie einfach
cat
die Quelldatei auf und leiten Sie ihre Ausgabe in die Zieldatei um.Das Gleiche ist falsch, wenn Sie
tr
früher anrufen .read
Legt den Wert einer Variablen fest, erzeugt jedoch keine Ausgabe, sodass das Weiterleitenread
an irgendetwas unsinnig ist.Es ist kein explizites Beenden erforderlich, es sei denn, der Benutzer sagt "Nein" (oder die Funktion stößt auf eine Fehlerbedingung wie in Teilen meines Codes, aber da es sich um eine Funktion handelt, die ich
return
eher verwende alsexit
).Sie sagten auch "Funktion", aber Ihre Implementierung ist ein Skript.
Schauen Sie sich https://www.shellcheck.net/ an , es ist ein gutes Werkzeug, um problematische Teile von Shell-Skripten zu identifizieren.
Die Verwendung
cat
ist nur eine Möglichkeit, den Inhalt einer Datei zu kopieren. Andere Möglichkeiten sinddd if="$1" of="$2" 2>/dev/null
sed "" "$1" >"2"
oderawk '1' "$1" >"$2"
odertr '.' '.' <"$1" >"$2"
usw.Das Knifflige ist, dass die Funktion die Metadaten (Besitz und Berechtigungen) von der Quelle zum Ziel kopiert.
Eine andere Sache, die zu beachten ist, ist, dass sich die von mir geschriebene Funktion ganz anders verhält, als
cp
wenn das Ziel beispielsweise so etwas wie/dev/tty
eine nicht reguläre Datei ist.quelle
cat "$1" >"$2"
wird in zwei> "$2"
Fällen funktionieren: Die Shell sieht zuerst , was bedeutet: Erstellen oder Clobber (= leer) der Datei "$ 2", und leiten Sie die Standardausgabe des Befehls in diese Datei um. Dann startet es den Befehl:cat "$1"
und leitet seine Standardausgabe in eine Datei um"$2"
(die bereits geleert oder leer erstellt wurde).-ef
Dateivergleiche als auch über gelerntlocal -a
.-ef
nimmt zur Kenntnis, ob die beiden Dateien identisch sind (kümmert sich auch um Links) undlocal -a
erstellt eine lokale Array-Variable.