Ich habe ein Skript, das alle Dateien in mehreren Unterordnern und Archiven nach tar durchsucht. Mein Drehbuch ist
for FILE in `find . -type f -name '*.*'`
do
if [[ ! -f archive.tar ]]; then
tar -cpf archive.tar $FILE
else
tar -upf archive.tar $FILE
fi
done
Der Befehl find gibt die folgende Ausgabe aus
find . -type f -iname '*.*'
./F1/F1-2013-03-19 160413.csv
./F1/F1-2013-03-19 164411.csv
./F1-FAILED/F2/F1-2013-03-19 154412.csv
./F1-FAILED/F3/F1-2011-10-02 212910.csv
./F1-ARCHIVE/F1-2012-06-30 004408.csv
./F1-ARCHIVE/F1-2012-05-08 190408.csv
Die Variable FILE speichert jedoch nur den ersten Teil des Pfads ./F1/F1-2013-03-19 und dann den nächsten Teil 160413.csv .
Ich habe versucht read
mit einer while-Schleife,
while read `find . -type f -iname '*.*'`; do ls $REPLY; done
aber ich bekomme folgenden fehler
bash: read: `./F1/F1-2013-03-19': not a valid identifier
Kann mir jemand einen alternativen Weg vorschlagen?
Aktualisieren
Wie in den Antworten unten vorgeschlagen, habe ich die Skripte aktualisiert
#!/bin/bash
INPUT_DIR=/usr/local/F1
cd $INPUT_DIR
for FILE in "$(find . -type f -iname '*.*')"
do
archive=archive.tar
if [ -f $archive ]; then
tar uvf $archive "$FILE"
else
tar -cvf $archive "$FILE"
fi
done
Die Ausgabe, die ich erhalte, ist
./test.sh
tar: ./F1/F1-2013-03-19 160413.csv\n./F1/F1-2013-03-19 164411.csv\n./F1/F1-2013-03-19 153413.csv\n./F1/F1-2013-03-19 154412.csv\n./F1/F1-2012-09-10 113409.csv\n./F1/F1-2013-03-19 152411.csv\n./.tar\n./F1-FAILED/F3/F1-2013-03-19 154412.csv\n./F1-FAILED/F3/F1-2013-03-19 170411.csv\n./F1-FAILED/F3/F1-2012-09-10 113409.csv\n./F1-FAILED/F2/F1-2011-10-03 113911.csv\n./F1-FAILED/F2/F1-2011-10-02 165908.csv\n./F1-FAILED/F2/F1-2011-10-02 212910.csv\n./F1-ARCHIVE/F1-2012-06-30 004408.csv\n./F1-ARCHIVE/F1-2011-08-17 133905.csv\n./F1-ARCHIVE/F1-2012-10-21 154410.csv\n./F1-ARCHIVE/F1-2012-05-08 190408.csv: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors
IFS=$'\n'
als ob Sie vor die `for-Schleife setzen sollten, damit sie von jeder Zeile analysiert wirdAntworten:
Die Verwendung von
for
withfind
ist hier der falsche Ansatz. Sehen Sie sich zum Beispiel diesen Artikel über die Dose Würmer an, die Sie öffnen.Der empfohlene Ansatz ist die Verwendung
find
,while
undread
wie hier . Nachfolgend finden Sie ein Beispiel, das für Sie funktionieren sollte:Auf diese Weise begrenzen Sie die Dateinamen mit Null (
\0
) - Zeichen. Dies bedeutet, dass Variationen im Leerzeichen und in anderen Sonderzeichen keine Probleme verursachen.Um ein Archiv mit den gefundenen Dateien zu aktualisieren
find
, können Sie die Ausgabe direkt antar
folgende Adresse übergeben :Beachten Sie, dass Sie nicht unterscheiden müssen, ob das Archiv existiert oder nicht,
tar
wird es sinnvoll behandeln. Beachten Sie auch die Verwendung von-printf
hier, um zu vermeiden, dass das./
Bit in das Archiv aufgenommen wird.quelle
./
as tar../.tar tar: ./archive.tar: file is the archive; not dumped
if [[ "$FILE" == "./" ]]; then
continue
./
Bit mit der-printf
aktualisierten Antwort umgehen . Es sollte jedoch keinen Unterschied machen, ob es enthalten ist oder nicht, da es nur auf das aktuelle Verzeichnis verweist. Ich habe auch eine alternativefind/tar
Kombination beigefügt , die Sie möglicherweise verwenden möchten.sort
die Ergebnisse vor der Iteration sehen möchten, benötigen Siesort -z
das Null-Trennzeichen.Versuchen Sie das zu zitieren
for
Schleife wie :Ohne Anführungszeichen kann bash mit Leerzeichen und Zeilenumbrüchen (
\n
) überhaupt nicht umgehen ...Versuchen Sie auch die Einstellung
quelle
comm
sortierte Dateilisten verglichen und die Dateinamen enthielten Leerzeichen, obwohl es nicht funktionierte, Variablen zu zitieren. Dann sah ich cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html und die Lösung, $ IFS mit IFS = $ (echo -en "\ n \ b") zu setzen, funktionierte für mich.Das funktioniert und ist einfacher:
Wir danken Rupa ( https://github.com/rupa/z ) für diese Antwort.
quelle
Zusätzlich zur korrekten Anführungszeichen können Sie die
find
Verwendung eines NULL-Trennzeichens angeben und dann die Ergebnisse in einerwhile
Schleife lesen und verarbeitenDies sollte alle Dateinamen behandeln, die POSIX-kompatibel sind - siehe
man find
quelle
quelle
Ich habe so etwas gemacht, um Dateien zu finden, die Leerzeichen enthalten können.
Lief wie am Schnürchen :)
quelle
Die meisten Antworten hier brechen ab, wenn der Dateiname ein Zeilenumbruchzeichen enthält. Ich benutze die Bash mehr als 15 Jahre, aber nur interaktiv.
In Python können Sie uns os.walk (): http://docs.python.org/2/library/os.html#os.walk
Und das Tarfile-Modul: http://docs.python.org/2/library/tarfile.html#tar-examples
quelle
Ich denke, Sie könnten besser dran sein
find
, wenn Sie die Option -exec verwenden.Find führt dann den Befehl über einen Systemaufruf aus, sodass Leerzeichen und Zeilenumbrüche erhalten bleiben (eher eine Pipe, für die Sonderzeichen in Anführungszeichen gesetzt werden müssten). Beachten Sie, dass "tar -c" funktioniert, unabhängig davon, ob das Archiv bereits existiert oder nicht, und dass (zumindest mit bash) weder {} noch + in Anführungszeichen gesetzt werden müssen.
quelle
Wie von minerz029 vorgeschlagen, müssen Sie die Erweiterung des
find
Befehls angeben . Sie müssen auch alle Substitutionen von$FILE
in Ihrer Schleife angeben.Beachten Sie, dass die
$()
Syntax der Verwendung von Backticks vorzuziehen ist. siehe diese U & L-Frage . Ich entfernte auch das[[
Schlüsselwort und ersetzte es durch den[
Befehl, weil es POSIX ist.quelle
[[
und[
scheint es, dass[[
es neuer ist und mehr Funktionen wie Globbing und Regex Matching unterstützt.[[
ist nur inbash
, aber nichtsh
[[
Globbing verstehen . Laut Gregs Wiki findet im Inneren kein Globbing statt[[
.[ "ab" == a? ] && echo "true"
dann[[ "ab" == a? ]] && echo "true"
a*
dies "gefolgt von einer beliebigen Anzahl von Zeichen" bedeutet und nicht "alle Dateien, deren Namen mita
einer beliebigen Anzahl von Zeichen beginnen und danach". Versuchen[ ab = a* ] && echo true
vs.[[ ab == a* ]] && echo true
.[[
tut noch reguläre Ausdrücke, während[
nicht. Muss verwirrt sein