
$ sh Backup-zu-s3.sh
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
ubuntu@accretive-staging-32gb-ephemeral:~$ cat Backup-to-s3.sh
#Script to move /home/ubuntu/backup folder to S3://auto-backup
#Author Ashish Karpe
cd /mnt/backup
filename="bkup_$(date +%Y%m%d_)"
/bin/ls -alF | awk '{ print $9 }' > /tmp/file
for i in $(cat /tmp/file); do
# echo $i;
# read a;
# echo $filename;
if [ $filename* = $i ]
then
echo "Copying " $i "to S3://auto-backup";
s3cmd put $i s3://auto-backup
fi
done
Antwort1
nicht verwenden,
for
um über die Zeilen einer Datei zu iterieren, verwendenwhile IFS= read -r line; do ...; done < filename
Sie müssen
ls
die Ausgabe überhaupt nicht in eine Datei umleiten,besondersmit-F
- Verwenden Sie Bash
[[ x == y ]]
für Mustervergleiche. Das Muster befindet sich auf der rechten Seite:
#!/bin/bash
cd /mnt/backup
prefix="bkup_$(date +%Y%m%d_)"
for file in * .*; do
[[ -f $file ]] || continue # skip things like directories and soft links
if [[ $file == $prefix* ]]; then
echo "Copying " $file "to S3://auto-backup";
s3cmd put $file s3://auto-backup
fi
done < /tmp/file
Antwort2
Auch wenn Sie die Ausgabe von „ls“ in eine Datei schreiben und diese analysieren, analysieren Sie indirekt die Ausgabe von „ls“, was entweder problematisch, eine wirklich schlechte Idee oder FALSCH!!! ist, je nachdem, wen Sie fragen.
Hier istwarum Sie die Ausgabe von 'ls' nicht analysieren sollten!
Hier istDateinamen und Pfadnamen in der Shell: So geht’s richtig!
Wenn beispielsweise eine der Dateien ein '-' (Bindestrich/Bindestrich) im Dateinamen hat, das nicht maskiert ist (durch vorangestellten Backslash ('\')), könnte es als Parameter interpretiert werden.
Das Parsen von „ls“ kann ganz einfach vermieden werden:
find . -maxdepth 1 -iname "*"
.
./dont_parse_ls.sh
./array.dat
./.bashrc
./BASH.Indirect.Reference.sh
./basharray.sh
./.forever
Das kommt auf das gleiche heraus wie
/bin/ls -alF | awk '{ print $9 }'
./
../
.bashrc
.forever/
BASH.Indirect.Reference.sh
array.dat
basharray.sh*
dont_parse_ls.sh
Ihre Ergebnisse sind variabel.
Antwort3
Das Skript weist mindestens zwei Hauptprobleme auf. Ihr grundlegendes Problem ist der Ausschnitt:
if [ $filename* =
Dies bringt einige Probleme mit sich. Erstens können Sie in Shell-Skripten kein Übereinstimmungsmuster „globben“. Das können Sie, aber wenn das Fileglob mehr als eine Übereinstimmung ergibt, erhalten Sie beide. In diesem Fall versucht das „[“-Programm (ja, es ist ein Programm), Folgendes auszuwerten:
filename1 filename2 filename3 = $i
Es funktioniert genau dann, wenn der Fileglob zu genau einem Dateinamen erweitert wird, und das können Sie selten garantieren. In Ihrem Fall wird $filename zu mindestens einer Datei erweitert, aber Sie sollten sich bewusst sein, dass dies nicht immer der Fall ist. Wenn „$file*“ zu gar keiner Datei erweitert wird, erhalten Sie möglicherweise (abhängig von einer Shopt-Einstellung) die leere Zeichenfolge:
= $i
was zum Scheitern führt [
. Mit dem richtigen Shopt erhalten Sie jedoch stattdessen:
backup-2014-whatever* = $i
Mit dem *
Teil des Vergleichs sein.
Das zweite grundlegende Problem ist die Verwendung des -F
Parameters in ls
. Dadurch wird ls angewiesen, an den Dateinamen eines von mehreren Zeichen anzuhängen, je nachdem, ob es sich bei der Datei um eine ausführbare Datei, einen Softlink usw. handelt.
NetScr1be ist da auf der richtigen Spur, aber Sie müssen nicht NetScr1bes Rat befolgen und niemals verwenden ls
... verwenden Sie einfach nicht ls -l
. Verwenden Sie stattdessen , ls -1
wodurch nur die Namen der Dateien in einer einzigen Spalte ohne Schnickschnack gedruckt werden. (Bei sehr großen Verzeichnissen werden sie sortiert, und das kann ein Problem sein. In diesem Fall gibt es eine Option ohne Sortierung; oder verwenden Sie find.)
Zur Erhöhung der Sicherheit sollten Ihre Variablen in doppelte Anführungszeichen gesetzt werden und sowohl LHS als auch RHS sollten mit einem Blindzeichen beginnen, um sicherzustellen, dass seltsame Dateinamen, die mit einem beginnen, -
nicht durcheinander geraten.
Ich würde mehr oder weniger Glenns Rat befolgen und es folgendermaßen machen:
command ls -1 | while read file; do
if [ x"$file" = x"$filename" ]]; then
echo Do Work Here
fi
done
So bin ichwürdetu es, aber Glenn hat mir freundlicherweise mitgeteilt, ich sollte es wirklich tunseinWeg:
for file in *; do
if [[ $file == $filename ]]; then ...
Antwort4
Dieses Skript erledigt alles. Warum nicht das? Die Shell wählt die richtigen Dateien für Sie aus, Sie müssen also nicht Folgendes aufrufen ls
:
#!/bin/sh
for file in /mnt/backup/bkup_$(date +%Y%m%d)_*
do
s3cmd put "$file" s3://auto-backup
done
- Der einzige externe Befehl ist
s3cmd
. - Keine
if
Aussagen. - Der einzige Entscheidungspunkt ist die
for
Schleife. - Leicht zu lesen.