Leerzeichen in Bash Array erhalten

spcqike

Lt. Commander
Registriert
Dez. 2008
Beiträge
1.548
Hallo zusammen,

ich weiß nicht, ob der Titel sinnvol gewählt wurde, oder ob er überhaupt mein Problem trifft, aber ich versuchs einfach mal :D Vielleicht versteht mich und mein Problem jemand.

Ausgangslage:
Ich möchte ich Bash Skript schreiben, welches mir die Größe aller Unterordner in einem Ordner auflistet, mich nach einer "Schwell-Größe" fragt und alle Ordner, die kleiner als besagte Schwelle sind, am Ende löschen lassen.

Das Skript, welches ich bisher habe, funktioniert, solange die Unterordner keine Leerzeichen haben. Leider bekomme ich das Problem der Leerzeichen nicht in den Griff.

Bash:
#!/bin/bash
#Definition zu prüfender Pfade
PFADE=("/Pfad/1/XYZ/" "/Pfad/2/XYZ/" )

#Auswahl des Pfads durch User
echo "Verfügbare Pfade:"
for ((i=0;i<=${#PFADE[@]}-1;i++));
do
echo $i" -"${PFADE[i]}
done
read -p "Welcher Pfad soll bereinigt werden? [0]: " antwort_pfad
antwort_pfad=${antwort_pfad:-0}

#Prüfen ob Pfad leer ist, ggf. Abbruch
if [ -z "$(ls -A "${PFADE[antwort_pfad]}")" ]; then
   echo "Abbruch, der Ordner ist leer!"
        exit 1
fi

PFAD="${PFADE[antwort_pfad]}"'/*'
echo $PFAD

#exit
#Auflistung der Ordner im Pfad -> speichern im Array
ORDNER=($(du -sm $PFAD))
#ORDNER=($(du -sm ${PFADE[antwort_pfad]}))
echo "Größe   : Ordner"
for ((i=0;i<=${#ORDNER[@]}-1;i+=2));
do
echo ${ORDNER[i]} "MB : "${ORDNER[i+1]}
done

exit

im Konkreten geht es mir um Zeile 20 bis 27.
Für die Auflistung der Unterordner mit Größe nutze ich "du -sm <Pfad/*>", was in der Konsole auch soweit funktioniert. nur leider im bash Skript nicht.

Die einzelnen Unterordner werden/sollten in ein Array übergeben werden, damit am Ende geprüft werden kann, welche Ordner zu löschen sind und diese entsprechend gelöscht werden.

Bash:
#Unter welcher Größe soll gelöscht werden?
read -p "Ab welcher Größe soll gelöscht werden? in MB [150]: " groesse
groesse=${groesse:-150}

#Frage ob gelöscht werden soll
read -p "Alle Ordner kleiner "$groesse" MB löschen? y/n [n]: " antwort
antwort=${antwort:-n}

#ggf. löschen
if [ $antwort = y ] || [ $antwort = Y ]
then
        for ((i=0;i<=${#ORDNER[@]}-1;i+=2));
        do
                if [ ${ORDNER[i]} -lt $groesse ]
                then
                rm -r ${ORDNER[i+1]}
                echo ${ORDNER[i+1]}" ("${ORDNER[i]}"MB) gelöscht!"
                fi
        done
else
echo "nichts gelöscht. Ende gut alles gut..."
fi

hat jemand eine Idee, was ich falsch mache? :D
 
Code:
IFS=$(echo -en "\n\b")
...kannst Du gebrauchen, wenn Du z.B. die Ausgabe von ls an ein Array geben willst. Ersetzt den Feldtrenner (normalerweile Leerzeichen), das neue Trennzeichen ist jetzt newline.

oder:
Code:
echo ${PFAD} | sed -e 's/ /\\ /g'
Ersetzt Dir " " durch "\ ".

Ein Setzen des Verzeichnisnamens in Anführungszeichen geht auch.
 
Zuletzt bearbeitet:
Hallo,

Danke für die Idee.
Ich werds im Laufe des Tages mal probieren einzubauen.

der Ansatz mit IFS wird nicht zielführend sein, da ich die Unterordner ja evtl. am Ende des Skripts löschen lassen will. das wird nicht gehen, wenn der String im Array ORDNER anders lautet, als der Ordner wirklich heißt.
Der Ansatz mit "sed" hingegen könnte was bewirken.

hast du eine Idee, wie ich das sinnvoll umsetze?

in Zeile 20 hänge ich ein einfaches "/*" an den ausgewählten PFADE String und lasse ihn mir testweise in Zeile 21 ausgeben. Leider sehe ich dort nicht den eigentlichen String, sondern bereits dessen "Auflösung", also alle Unterordner. ich befürchte, dass ein "sed" an dieser Stelle dazu führt, dass die Auflistung der Ordner in einem einzelnen String endet :) Werde es aber testen.

am liebsten würde ich das Anhängen des "/" erst in Zeile 25 vornehmen, da wo auch die Ausgabe von "du -sm" die eigentlichen Unterordner inkl. deren Größe anzeigen und in das Array übergeben soll. aber wenn ich es dort erst anhänge, bekomme ich immer den Fehler "du Pfad nicht gefunden" inkl. des eigentlich korrekten Strings, so wie ich ihn auch in der Kommandozeile eingeben kann (/Path/1/XYZ/)
 
Dein größtes Problem liegt darin, daß Du sowohl die Größe des Verzeichnisses als auch den Namen als eigene Elemente in das selbe Array packst, und das im gleichen Arbeitsschritt.

Sinnvoller wäre es, Namen und Größe in jeweils eigene arrays zu packen. So kannst Du die Namen der Verzeichnisse beliebig manipulieren (schon beim Füllen des Arrays) und brauchst nicht zu befürchten, und die Größenangaben kommen Dir nicht mehr in die Quere.
 
Hallo,

das habe ich mit dem "sed" Ansatz probiert. Leider bekomme ich da aber entweder einen einzelnen String (alle Unterordner werden aneinander gereiht, Leerzeichen dabei durch "\ " ersetzt), oder er teilt die Pfade weiterhin an jedem Leerzeichen und macht aus "/Pfad/1/aa bb" im Array zwei Elemente ("/Pfad/1/aa" und "bb") :(
 
Probier dies:
Code:
shopt -s nullglob # Vermeiden einer Fehlermeldung, sollte es doch keine Unterverzeichnisse geben
ORDNER=( ${PFAD}/*/ )
shopt -u nullglob
for ((i=0;i<=${#ORDNER[@]}-1;i++)); do
    SIZE[$i]=$(du -sm "${ORDNER[$i]}" | awk '{print $1}')
done
echo "Größe   : Ordner"
for ((i=0;i<=${#ORDNER[@]}-1;i++)); do
    echo "${SIZE[$i]} MB : ${ORDNER[$i]}"
done
Ergänzung ()

Bemerke Zeile 5: Das Element kann Leerzeichen enthalten, daher wird die Variable in Anführungszeichen gesetzt, damit 'du' es auch als ein einzelnes Element erkennt.
Der Trick der Definition hingegen liegt in Zeile 2, in der direkt das Verzeichnis (bzw. die Unterverzeichnisse) ohne Umwege über ls oder du ins Array eingelesen werden.
 
  • Gefällt mir
Reaktionen: spcqike
ich wollt mich nochmal kurz zurück melden :)
mit deinen anregungen habe ich es dann so in der art hinbekommen.
zuerst das array der Ordner, danach das Array der Größen.

Vielen Dank :)
 
Macht die Sache letztlich einfacher, zumindest in meinen Augen.

Ich biete Dir noch ein weiteres Snippet an, wenn Du eine Auswahl aus einer Liste machen möchtest (ist ein Ausschnitt aus einem anderen Script, als Denkanstoß und zum rumprobieren, nimmt auch Bezug auf eine Unterfunktion, die jetzt nicht enthalten ist):

Code:
f_snap_delete(){ ##benötigt Parameter DATASET in Form von POOL/DATASET
    f_ds_select
    SAVEIFS=$IFS
    IFS=$(echo -en "\n\b")
    OPTIONS=( $(zfs list -t snapshot -o name,used,referenced,compressratio,refcompressratio,creation -r ${DATASET} -d1 -S creation | tail -n +2) )
    IFS=$SAVEIFS

#sub-fkt
    f_menu() {
        echo "Verfügbare Snapshots:"
        for i in ${!OPTIONS[@]}; do
            printf "%3d%s) %s\n" $((i+1)) "${CHOICES[i]:- }" "${OPTIONS[i]}"
        done
        [[ "$MSG" ]] && echo -e "$MSG"; :
    }
#end sub-fkt

    clear
    echo ""
    PROMPT="Wählen Sie einen Snapshot (erneut zum abwählen, ENTER zum beenden): "
    while clear && echo "" && f_menu && read -rp "${PROMPT}" NUM && [[ "${NUM}" ]]; do
        [[ "${NUM}" != *[![:digit:]]* ]] && (( NUM > 0 && NUM <= ${#OPTIONS[@]} )) || {
            MSG="ungülgige Auswahl: ${NUM}"; continue
        }
        ((NUM--)); MSG="${BLUE}$(echo ${OPTIONS[NUM]}| awk '{print $1}') ${NORMAL}wurde ${CHOICES[NUM]:+ab}gewählt"
        ##${BLUE} und ${NORMAL} beziehen sich auf Zeichenfarben, wurden zuvor definiert und sind hier nicht enthalten
        [[ "${CHOICES[NUM]}" ]] && CHOICES[NUM]="" || CHOICES[NUM]="+"
    done

    printf "Ausgewählte Snapshots: "; MSG="Keiner."
    for i in ${!OPTIONS[@]}; do
        [[ "${CHOICES[i]}" ]] && { printf " %s" "$(echo ${OPTIONS[i]} |awk '{print $1}')"; MSG=""; }
    done
    echo "${MSG}"

    if [ ! "${MSG}" = "Keiner." ]; then
        f_yesno ##nicht enthalten in diesem snippet, ist eine Sicherheitsabfrage
        if [ "${YESNO}" = "YES" ]; then
            for i in ${!OPTIONS[@]}; do
                [[ "${CHOICES[i]}" ]] &&  zfs destroy $(echo ${OPTIONS[i]} |awk '{print $1}')
            done
            break
        else
            echo "abgebrochen."
            break
        fi
    fi
}
 
Zurück
Oben