bash: if ... then do...done fi exit

stefkey

Member
Hallo,

sagt mal, geht denn folgendes Kontrukt nicht?

Code:
if [ -s "$file" ] ;
then
do
echo "$file"
...
done

fi

exit 0

Es soll einfach bevor eine es in eine do Schleife reingeht geprüft werden ob das File auch größer 0 Byte ist. Mein Konstrukt funktioniert aber nich :confused:
 
Code:
if [ -s "$file" ]; then
    echo "$file"
fi
exit 0

Falls danach suchen willst, dann nuzte lieber find. Ist perfomanter als das Globbing oder abarbeiten der Ausgabe in einer Schleife.
 
Last edited by a moderator:
gibt es nicht

es gibt die Konstrukte:

Code:
while foo; do
    bar
done

for i in $f; do
    foo $i
done

if foo; then
    bar
elif foo2;
   bar2
elif n;
    barn
else;
    foobar
fi

Kann sein, dass jetzt Fehler drin sind. Bin eher Python gewöhnt. Da hat man weitaus weniger Zeichensalat. Für einfach Sachen bist du mit Shellscripting aber schon bei der richtigen Sprache. quick & dirty-

Sieh dir am besten ein paar Dokus zur Shell an. Shell-Scripting kann jeder. Shell-Scripts so schreiben, dass es andere noch verstehen, ist nicht ganz so einfach.
 
Last edited by a moderator:
Vielen Dank DeaD_EyE!

dann muss ich diese Abfrage ob die Datei größer 0Byte ist wohl in die do-Anweisung schreiben. Ich wollte ja eigentlich nur dann in die do-Anweisung wenn eben die Datei größer 0 Byte ist.

Nun ergibt sich noch folgendes Problem:
file=find irgendwas
cp $file /irgendwohin

In der Variable file seht nun eine Datei deren Pfad aber Leerzeichen hat. cp kann dann aber nicht mehr das tun was es soll. Oder?
Muss ich dann mit sed die Leerzeichen suchen und entsprechend richtig ersetzten mit Backslash.

Oder gibts noch ne andere Möglichkeit den Pfad gleich mit den richtigen Backslashes zu erhalten?
 
Code:
find . -type f -size +0c -exec cp {} /irgendwohin \;
Sucht in '.' nach Dateien größer als Null Bytes und kopiert sie nach /irgendwohin. Funktioniert auch mit Whitespaces in den Datei-/Ordnernamen.

Dürfte in etwa das sein was du suchst? Ansonsten $file bspw mit "" umschließen. Dann klappt es mit den Leerzeichen auch.
 
Code:
find . -type f -size +0c -exec cp {} /irgendwohin \;

ist nicht so effizient wie:

Code:
find . -type f -size +0c -print0 | xargs -0I{} cp {} /irgendwohin/

Anstelle von -size +0c (alles was größer als 0 Byte ist), kannst du auch ! -empty für den Test verwenden. Sähe dann so aus:

Code:
find . -type f ! -empty -print0 | xargs -0I{} cp {} /irgendwohin/

Wenn ich mich jetzt nicht gewaltig irre, brauchst du den String, der ersetzt werden soll, in diesem Fall {} nicht escapen, da xargs dem Befehl cp die Argumente übergibt. In diesem Fall spielt es keine Rolle, was in der Shell der delimiter ist.

Durch -print0 Treffer durch find mit einem nullbyte separiert. Xargs liest die Ausgabe von find ein (PIPE). Damit xargs auch das nullbyte als Seperator erkennt, musst du dann xargs -0 verwenden. -I{} ist dann der zu ersetzende Suchstring.

xargs versucht so viele Argumente wie möglich an den Befehl zu übergeben. Ab einem gewissen Limit, wird der Rest auf die nächsten Instanzen an den Befehl übergeben. Möchte man mehr Parallelität, kann man xrags -Pn verwenden. Wobei n die Anzahl der gleichzeitigen Prozesse angibt. Bei Dateioperationen ist das aber nicht sinnvoll, es seiden es hängt eine SSD dran.

Ich hab früher selbst vieles gescriptet und hab versucht so effizient wie möglich zu sein. Als ich mit xargs noch nichts mit anzufangen wusste, hatte ich so ähnliche Konstruke wie find foo; while read file; do foo $file; done oder find foo -exec foo {} /bar/ \;

Beide Konstrukte führt bei jedem Treffer ein bzw. mehrere Childprozesse aus. Bei 2 Dateien ist es völlig egal, bei 20.000 dauert zur Abarbeitung länger.
 
Hey danke für die Antworten. DeaD_EyE deine letzte Antwort werde ich auschecken...

Noch eine Zwischenfrage:
kann ich statt -s als if-Argument auch ein Datum nehmen?
Ich würde gerne prüfen ob eine Datei jünger als zB. 01.01.2013 ist.
Hat da jemand ne Lösung aus dem Stegreif?
 
Code:
man find

Code:
   TESTS
       Some tests, for example -newerXY and -samefile, allow comparison between the file currently being examined and some reference file specified on the command line.  When these tests are used,  the
       interpretation  of  the  reference file is determined by the options -H, -L and -P and any previous -follow, but the reference file is only examined once, at the time the command line is parsed.
       If the reference file cannot be examined (for example, the stat(2) system call fails for it), an error message is issued, and find exits with a nonzero status.

       Numeric arguments can be specified as

       +n     for greater than n,

       -n     for less than n,

       n      for exactly n.

....

       -mmin n
              File's data was last modified n minutes ago.

       -mtime n
              File's data was last modified n*24 hours ago.  See the comments for -atime to understand how rounding affects the interpretation of file modification times.

Code:
find /foo -type f -mtime 180

Wenn du mit dem Datum arbeiten willst, musst du das vorher umrechnen.

Code:
find -type f -mtime -$(expr \( `date +%s` - `date -d "2013-01-01" +%s` \) / 86400)

Wichtig ist, dass man bei Verwendung von expr die Zeichen vor der Shell escapen muss.

Aus ( und ) wird \( und \)
Aus * wird \*

Wenn du den Befehl verstehen willst, dass lies dir die manpages zu find, expr und Date durch.

Am besten noch über Kommandosubstitution: Backticks ` und POSIX-Standard: $()

Nicht alles was du in der bash machst, ist kompatibel zu den anderen Shells. Da gibt es Unterschiede.
 
Vielen vielen Dank DeaD_EyE für deine Hinweise!

Ich muß doch genauer erklären was das script machen soll:

1. Finde alle Dateien in /Volumes/squeeze mit Datum neuer als 01.01.2011 dann soll folgendes abgearbeitet werden. Gelöst mit:
Code:
find /Volumes/squeeze -newermt 2011-01-01 | while read file
2. Die gefundene Datei soll mit einer Datei aus dem Backup überschrieben werden wenn der Timestamp dieser Datei aus dem Backup vor dem 01.01.2011 ist. Ansatzweise gelöst mit:
Code:
backup = `echo $file | sed 's/^\/Volumes\/squeeze\//\/Volumes\/backup\/2013-03-01\//g'`

if [ $backup-Timestamp vor dem Datum 01.01.2011 ] dann
cp -a "$backup" "$file"
fi
done
exit 0



Ich denke ich muss nun die beiden Timestamp in 2 Variablen schreiben(timestampbackup = touch -r $backup und timestampfile = touch -r $file)
und diese dann in diese beiden Variablen dann im if verbauen.
Daher meine obige Frage:
kann ich statt -s als if-Argument auch ein Datum nehmen?
Ich würde gerne prüfen ob eine Datei jünger als zB. 01.01.2013 ist.
Hat da jemand ne Lösung aus dem Stegreif?
 
Back
Top