• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

[erledigt] bash if und negierter regulärer Ausdruck

Moin Moin,

ich hätte da gern mal wieder ein Problem...

Ich will zwei Verzeichnisse vergleichen und die geänderten Dateien in ein 3tes Verzeichnis kopieren. Dazu fiel mir nichts besseres als rsync ein. Folgendes hab ich jetzt soweit zusammen:
Code:
if [ ! -e /sicherung-$1 ]
then
mkdir /sicherung-$1
else
echo "Dieses Verzeichnis wurde hier schon gesichert!"
exit 1
fi

IFS=$'\n'
for blubb in `rsync -avn /test-zu-sichernd/ /test-orig/`
do
    if [[ $blubb =~ 'sending incremental' ]] || [[ $blubb =~ 'sent ' ]] || [[ $blubb =~ './' ]] || [[ $blubb =~ 'total size is' ]]
    then
	continue
    else
	cp /test-zu-sichernd/$blubb /sicherung-$1/$blubb
    fi
done
Macht jetzt erstmal nur für ein Verzeichnis, sollen aber mehr werden. Funktioniert soweit, gefällt mir aber nicht aus folgenden Gründen:
Erstens kommt mir im if zu häufig das Gleiche vor, ich würde wesentlich lieber nur die Pattern per ODER angeben
Zweitens betreibe ich hier nur globbing und kein patternmatching, schöner wäre es auf "Zeile beginnt mit " zu testen
Drittens würde ich den Ausdruck negieren wollen um then und else in einer verständlicheren Reihenfolge zu haben

Letztlich sollte sowas raus kommen:
WENN $blubb NICHT mit "sending" BEGINNT ODER mit sent BEGINNT ODER mit ./ BEGINNT DANN kopiere

Aber egal ob ich mich mit -ne oder !=, mit einfachen runden Klammern oder halt den jetzt verwendeten doppelten eckigen versucht hab, bin ich immer wieder grandios an der Kombination NICHT, regulärer Ausdruck, ODER gescheitert.

Letzter Ausweg für mich wäre jetzt die Ausgabe von rsync in eine temporäre Datei zu leiten, die Zeilen die nicht Dateinamen enthalten per sed durch nichts zu substituieren, über diese Datei mittels for zu iterieren um das Kopieren zu machen und am Ende die Datei wieder zu löschen. Aber das muß doch auch so über eine Variable gehen...
 
Geier0815 schrieb:
WENN $blubb NICHT mit "sending" BEGINNT ODER mit sent BEGINNT ODER mit ./ BEGINNT DANN kopiere
Wenn $blubb mit sent beginnt, beginnt es mal nicht mit sending, das ODER wird dann also nicht mehr getestet. Die Logik ist also falsch. Sollte da nicht ein UND hin?

Dann sähe es so aus:
Code:
if [[ ! $blubb =~ ^sending ]] && [[ $blubb =~ ^sent|^./ ]]; then
  echo kopiere
fi
 
Stell dir den Ausdruck geklammert vor
! (sending|sent|./)
dh er prüft erst auf sending wahr oder falsch. sending ==wahr , der gesamtausdruck wahr und dann durch das ! negiert damit kein kopieren. sending ==falsch, guck ob sent wahr oder falsch etc.
 
Ich würde mir der Übersichtlichkeit halber mehrere if-Bedingungen, ggf. mit einer zusätzlichgen Varialbe gönnen:
Code:
#!/bin/bash

blubb="./sendingsda"

do_copy=0

if [[ ! $blubb =~ ^sending ]]; then do_copy=1; fi

if [[ $blubb =~ ^sent ]]; then do_copy=1; fi

if [[ $blubb =~ ^./ ]]; then do_copy=1; fi

if [ $do_copy = 1 ]; then
    echo "kopiere"
fi
Der Ausdruck mit "|" oben wirft bei mir sowieso 'nen Fehler (keine Ahnung, warum).
 

framp

Moderator
Teammitglied
Ich würde es so machen:
Code:
#!/bin/bash

function test() {

local blub=$1

regex="^(sending|sent|./|total size is)"

if [[ $blub =~ $regex ]] ; then
	echo "$1: match"
else
	echo "$1: fail"
fi
}

test "xsending"
test "sending"
test "sent"
test "xsent"
test "./"
test "x./"
test "total size is"
test "xtotal size is"

Und die Ausgabe dazu
Code:
framp@obelix ~/scripts $ ./blub.sh
xsending: fail
sending: match
sent: match
xsent: fail
./: match
x./: fail
total size is: match
xtotal size is: fail

Allerdings finde ich den Weg die Ausnahmen auszuschliessen nicht so sicher. Ich wuerde eher die gesuchten Zeilen per Regex finden.
 
A

Anonymous

Gast
Sicherlich könnte man das in einer einzigen IF-Abfrage testen, aber das wird extrem unübersichtlich und kaum sonderlich wartungsfreundlich, schwer eventuelle Risiken und Nebenwirkungen vorrauszusagen, bzw zu eliminieren.
abgdf schrieb:
Ich würde mir der Übersichtlichkeit halber mehrere if-Bedingungen, ggf. mit einer zusätzlichgen Varialbe gönnen:.......
Das wäre meiner Meinung nach auch der bessere Ansatzpunkt, aber bei mehrfachen Suchpattern in der selben Variable bitte nicht mit if sondern mit case

Beispiel mit Testschleife :
Code:
for blubb in "sending müll" sentmüll ./mülleimer mülleimer "müll sending"  
do  
   echo -ne "$blubb \t\t\t: " 

   case $blubb in  
       sending*|sent*|./*)    echo ;;
                        *)    echo   "wird kopiert" ;;
   esac 
done
Wartungsfreundlich, sogar noch vereinfachbar (jedes Pattern eigene Zeile), universell und unbegrenzt erweiterbar ohne das man große Verrenkungen auf der Shell machen muss.
Das etwas Unschöne an case, (dass sich hier in der Aufgabe allerdings recht praktisch erweist) es stehen faktisch für die Suchpattern nur die Methoden der Pathnamen Erweiterung zur Verfügung. Da es sich aber hier in der Aufgabe um Dateinamen handelt ist das nahezu genial einfach zu schreiben.

robi
 
Upps, hier bin ich noch die Auflösung schuldig wie ich es letztlich gebaut habe.
Code:
sicher_verzeichnis(){
sync=`rsync -avn /$1/ $orig/$1/`
regex='^sending\|^sent\|^\.\/$\|~$\|^total\ size\|\/$\|->\|^created\ directory'
name_liste=`echo $1 | sed 's/\//-/g' `

if [ ! -e $gesichert ]
then
mkdir $gesichert
fi

IFS=$'\n'
for zeile in $sync
do
    echo $zeile | sed "/$regex/ d" >> $gesichert/$name_liste.tmp
done

for zeile in `cat $gesichert/$name_liste.tmp`
do
    cp --parents /$1/$zeile $gesichert
done
}

Wie zu sehen hab ich das Ganze nun als Funktion gebaut und auf die Negation verzichtet. $orig und $gesichert werden vorher global gesetzt und der Verzeichnisname beim Aufruf der Funktion übergeben. Symbolischen Links wird nicht gefolgt.
Noch ein paar Anmerkungen: Ich hab zu Anfang echt lange gebraucht um dahinter zu steigen das das ODER nur funktioniert wenn man es mit dem Backslash schützt. Um darauf zu kommen, hab ich einfach angefangen mit dem einfachen grep zu spielen, das verwendet offensichtlich die gleiche RegEx-Syntax wie sed.
Und was ich lernen mußte war das man versuchen muß so einfach wie möglich zu denken. Ich war irgendwann mal an einem Punkt angekommen wo ich Gänsefüßchen in Hochkommas verwenden wollte weil ein Teil von der bash als Variable interpretiert werden sollte und der Rest nicht...
Und das Lesen der man-pages bildet. Bis dato kannte ich die Option "--parents" von cp nämlich auch noch nicht.
 
Oben