Mehrere Verzeichnisse nach best. Dateien/Verz. durchsuchen

Dieses Thema im Forum "Shell-Skripte" wurde erstellt von Morth, 09.04.2010.

  1. Morth

    Morth Grünschnabel

    Dabei seit:
    09.04.2010
    Beiträge:
    6
    Zustimmungen:
    0
    Hi,
    ich bin neu hier und auch shell-programmierung ist für mich recht neu. Aber ich verzweifle langsam und daher hoffe ich ihr könnt mir weiter helfen.

    Ubuntu 4.2.4 mit bash

    Also:
    ich möchte mehrere, bestimmte verzeichnisse nach leerzeichen untersuchen. Je nach fund soll ein bestimmter exit-code gesetzt werden. Das habe ich auch schon geschafft, solange ich nur ein verzeichnis untersuchen will. Aber ich bekomme das absolut nicht hin es für mehrer in einem abwasch zu machen.

    hier erstmal meine einzellösung:

    Code:
    #!/bin/sh
    
    MATCHES_SPACE_1=`find "$1" -maxdepth 1 -regextype posix-extended -regex "^$1/[^ ]*[ ]+[^ ]*$" -printf "%f\n"`
    
    MATCHES_SPACE_3=`find "$1" -maxdepth 1 -regextype posix-extended -regex "^$1/[^ ]*[ ]{3,}[^ ]*$" -printf "%f\n"`
    
    if      [ \( -n "${MATCHES_SPACE_1}" \) -a \( -n "${MATCHES_SPACE_3}" \) ]; then
              echo "CRITICAL: Verzeichnisse/Dateien mit einem oder mehr UND drei oder mehr aufeinander folgenden Leerzeichen gefunden! $1"
              exit 2
    elif    [ -n "${MATCHES_SPACE_3}" ]; then
              echo "CRITICAL: Verzeichnisse/Dateien mit drei oder mehr aufeinander folgenden Leerzeichen gefunden! $1"
              exit 2
    elif    [ -n "${MATCHES_SPACE_1}" ]; then
              echo "CRITICAL: Verzeichnisse/Dateien mit einem oder mehr aufeinander folgenden Leerzeichen gefunden $1"
              exit 2
    else      echo "OK: keine Dateien oder Verzeichnisse mit Leerzeichen gefunden $1"
              exit 0
    fi
    
    starten würde ich das ganze mit check.sh /verzeichnis

    achja, die verzeichnisse sollen im script stehen und nicht aus einer anderen datei geladen werden, das ist gerade mein grossen problem.

    hoffe ihr könnt damit was anfangen ;)

    Grüsse, Simon
     
  2. Anzeige

    Schau dir mal diese Kategorie an. Dort findest du bestimmt etwas.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  3. #2 bytepool, 09.04.2010
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Hi,

    wo ist jetzt das Problem? Einfach -maxdepth weglassen, und du hast doch schon was du suchst?

    mfg,
    bytepool
     
  4. #3 ar0, 09.04.2010
    Zuletzt bearbeitet: 09.04.2010
    ar0

    ar0 Jungspund

    Dabei seit:
    29.03.2010
    Beiträge:
    17
    Zustimmungen:
    0
    1. Wie willst du mehrmals einen exitcode setzen? Du kannst dein Skript schließlich nur einmal beenden.
    2. deine Regexes machen nicht was du denkst/willst.
    Code:
    $ echo '/foo bar'        |egrep '^/[^ ]*[ ]+[^ ]*$'  # ok soweit.
    $ echo '/foo bar baz'  |egrep '^/[^ ]*[ ]+[^ ]*$'  # whoops.
    
    Gut wäre imho auch den String erstmal soweit zu bearbeiten, dass du nicht immer "^$1/" mitmatchen musst, weil dann reicht als Regex einfach "[ ]+".
    3.
    Nach dem ersten quote zu urteilen würd ich sagen, dass das Verzeichnis als Parameter übergeben werden soll, nach dem zweiten quote nicht.

    Und zu guter letzt würde ich zu einer Schleife der Art
    Code:
    find "$1" -type d|while read dir; do
        # mach was du machen willst
    done
    
    übergehen. Damit läufst du nur einmal über die Verzeichnisse.
    Noch ein Trick zum Leerzeichen zählen:
    Code:
    $ echo "a aaa    a a      a a                  a a a aaaa  a " |
      perl -ne 'printf "%d\n", length $_ for /[ ]+/g'
    
    Das kann man auch mit vielen pipes und "shell-Mitteln" machen (mir fällt spontan egrep -o, wc -c und expr ein), aber ich würd sagen das machts nicht unbedingt einfacher. Diese Ausgabe kannst jetzt natürlich noch mit sort und uniq bearbeiten.
     
  5. #4 Morth, 10.04.2010
    Zuletzt bearbeitet: 10.04.2010
    Morth

    Morth Grünschnabel

    Dabei seit:
    09.04.2010
    Beiträge:
    6
    Zustimmungen:
    0
    joa das ist ja auch mein problem, ich muss die überprüfung der verzeichnisse irgendwie vorher machen

    hmm aalso ich dachte ich hätte alles durchgespielt, aber wenn ich die grenzen weglasse müsste das allerdings reichen... teste ich morgen mal... ich hab halt noch nicht so den überblick mit welchen befehlen was machen kann und welche parameter man da am besten nimmt.
    also ich dachte so an find, awk und egrep, aber für tips bin ich dankbar

    also ich würde ja auch gerne dann die verzeichnisse in eine variable oder in mehrere schreiben, wenn das irgendwie geht sowas wie
    Code:
    Liste=( vz1 vz2 vz3)
    
    aber keine ahnung ob sowas geht oder halt
    Code:
    vz1="/verzeichnis1"
    vz2="/verzeich/nis2"
    
    ja eine schleife wäre mein nächster anlauf gewesen, aber irgendwie fehlt mir der ansatz, wie ich das mit mehreren verzeichnissen mache

    puuh ja ich weiss, perl ist da viel mächtiger, aber das kann ich noch wenier :(
    naja ich glaub das hilft aber nix, ohne daraus ein monster zu machen
    .
    .
    .
    EDIT (autom. Beitragszusammenführung) :
    .

    joa, aber alles in unterverzeichnissen interessiert mich nicht. die verzeichnisse sollen beliebig wählbar sein und nur in deren ebene gesucht werden
     
  6. ar0

    ar0 Jungspund

    Dabei seit:
    29.03.2010
    Beiträge:
    17
    Zustimmungen:
    0
    Hm, ich hab meine Verwirrung wohl nicht klar genug gemacht. Ich versteh einfach nicht was du genau machen willst.

    Soll das Skript mit exit-code 2 enden falls in einem der (auf der Kommandozeile übergebenen) Verzeichnisse ein Verzeichnis mit Leerzeichen enthalten ist? (In der "ersten Ebene", also find -maxdepth 1)
    Falls ja, dann kannst du doch einfach alle Verzeichnisse entsprechend testen und einfach beim ersten Leerzeichen "exit 2" machen. (Oder hab ich was falsch verstanden?)
    Falls nein versteh ich nicht wie das funktionieren soll, aber du könntest es vielleicht mit einer Variable machen und am Ende des Skripts einfach 'exit $exit_var' oder so.

    Ja natürlich geht das, meine Frage war eher, wo kommen die Verzeichnisse her, von der Kommandozeile?
    Falls ja, so sind sie bereits in einem Array:
    Code:
    $ cat foo.sh
    #!/bin/sh
    for arg in "$@"; do
        echo "$arg"
    done
    $ ./foo.sh '/foo' './bar baz/asdf' '/  setsamer/verzeichnis/name/'
    /foo
    ./bar baz/asdf
    /  setsamer/verzeichnis/name/
    
    Zur while-Schleife: wenn ich dich diesmal richtig(er) verstehe, dann sollte das eine geschachtelte Schleife sein, "außen" über die Verzeichnisnamen und innen über die "Inhalte" (also das, was find "$verzeichnisname" -maxdepth 1 liefert) iterieren, wobei die äußere Schleife dann wie oben eine for- und die innere Schleife wie im letzten Post eine while-Schleife wär.
    Aber das sind nur Empfehlungen, machs so wie dus verstehst.

    Btw, du packst Verzeichnisnamen in deinem find-Einzeiler einfach in eine Regex ohne Sonderzeichen entsprechend zu escapen. (Was wenn $1="[]"? Syntaxfehler, whoops..) Und damit will ich *nicht* suggerieren, dass du jetzt die Dinger erst escapen und dann in die Regex stecken sollst. Eher würd ich, wie im vorigen Post schon vorgeschlagen, sehen, dass du den Anfang ("^$1/") nicht jedesmal mitmatchen musst; denn das ist fehleranfällig und redundant.
     
  7. #6 bytepool, 10.04.2010
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Hi,
    ah, das ist der Knackpunkt, das hatte ich nicht verstanden. Ich denke dann habe ich jetzt ungefaehr verstanden was du willst, aber du solltest in Zukunft versuchen im ersten Post noch deutlicher zu sein. Mir ist klar dass eine gute Beschreibung nicht immer einfach ist, erst Recht wenn man selbst schon voll drin steckt. Aber wenn das Problem nicht verstanden wird, kann man dir nicht helfen, wie du ja vielleicht auch an unseren Fragen merkst.

    In dem Fall halte ich find fuer ziemlich ueberfluessig. Dann wuerde ich die Verzeichnisse lieber in einen Array schreiben und ueber alle Dateien in dem Verzeichnis via globbing iterieren. Dann kannst du naemlich in aller Ruhe pro Dateiname alle moeglichen tests durchfuehren die dir in den Sinn kommen, ohne dich selbst auf eine regex zu beschraenken.

    z.B. so in der Art, um ar0's Beispiel mal aufzugreifen:
    Code:
    for dir in "$@"; do
        for file in "$dir/*"; do
    	echo "$file" # processing here                                                           
        done
    done
    
    Das ist einfach flexibler. Aber es gilt wie immer, viele Wege fuehren nach Rom, es geht sicher auch mit find und regexen (eine neue Echsenart, legen auch Eier, fressen sie aber nicht).

    mfg,
    bytepool
     
  8. Morth

    Morth Grünschnabel

    Dabei seit:
    09.04.2010
    Beiträge:
    6
    Zustimmungen:
    0
    sry wenn ich das vielleicht nicht so richtig rüber gebracht habe, aber ich versuche mein bestes. ist alles totales neuland für mich und ich versuche mein bestes nicht alles durcheinander zu schmeissen.

    ich danke euch schon mal sehr für eure hartnäckigen Bemühungen mir zu helfen. Hier kamen jetzt gleich mal 4 oder 5 Begriffe die wohl wichtig sind und ich muss jetzt erstmal wieder ne ganze Weile Manuals studieren. Ich hab einfach noch nicht den überblick, welche werkzeuge ich alles habe.

    aber das mit array hört sich schon mal sehr gut an, das kenne ich aus C.

    die Verzeichnisse sollen im script dann "hardcoded" werden.

    so ich werd mal machen und melde mich wenn ichs hinbekommen habe oder euch weiter nerven muss ;)
     
  9. Morth

    Morth Grünschnabel

    Dabei seit:
    09.04.2010
    Beiträge:
    6
    Zustimmungen:
    0
    So ich habe das mal getestet. Es funktioniert auch wunderbar, nur habe ich jetzt ein neues Problem:
    bei

    for VARIABLE in WORT do

    werden die Elemente in WORT durch Leerzeichen getrennt. Nun habe ich aber gerade Elemente, die x Leerzeichen enthalten können. Somit werden die ursprünglichen Elemente zerstückelt.

    Ich hatte das z.B. so gemacht:

    Code:
    #!/bin/bash
    VERZEICHNISSE="/var /var/www"
    
    for dir in "$VERZEICHNISSE"; do
        for file in `ls -A $dir`; do
            echo "$file" # processing here
         done
    done
    
    Wenn ich z.B. eine Datei "test test" habe kommt als Ausgabe

    test
    test

    raus.

    Irgendwie müsste das Zeilenweise gehen, dann wärs kein Problem denke ich.
     
  10. #9 ar0, 13.04.2010
    Zuletzt bearbeitet: 13.04.2010
    ar0

    ar0 Jungspund

    Dabei seit:
    29.03.2010
    Beiträge:
    17
    Zustimmungen:
    0
    Wenn dus denn unbedingt hardcoden willst, pack die Verzeichnisse halt in ein Array.
    Code:
    $ cat foo.sh
    #!/bin/sh
    dirs=( "/foo" "./bar baz/asdf" "/  setsamer/verzeichnis/name/" )
    
    for dir in "${dirs[@]}"; do
        echo "$dir"
    done
    $ ./foo.sh
    /foo
    ./bar baz/asdf
    /  setsamer/verzeichnis/name/
    
    relevanter Teil von man bash:
    Code:
    If
           the word is double-quoted, ${name[*]} expands to a single word with the
           value  of each array member separated by the first character of the IFS
           special variable, and ${name[@]} expands each element of name to a sep‐
           arate  word.   When  there  are no array members, ${name[@]} expands to
           nothing.
    Das der obige code so funktioniert ist also kein Zufall, sondern per Design.
    bash expandiert "${a[@]}" zu "${a[0]}" "${a[1]}" etc., also perfekt für for-Schleifen. (Und btw, "$@" expandiert analog zu "$1" "$2" etc.)

    edit:
    und für die innere Schleife würde ich wieder eine while-read Kombo empfehlen. Entweder mit "ls -a1" oder "find -maxdepth 1".
     
  11. #10 bytepool, 13.04.2010
    Zuletzt bearbeitet: 13.04.2010
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Nicht ganz, du hast das globbing (/*) druch eine sub-shell (`ls -A $dir`) ersetzt, was zu deinem Problem fuehrt. Aber ich kann verstehen dass der Unterschied fuer einen Skripting Neuling nicht direkt ersichtlich ist.

    Mache aus `ls -A $dir` wieder "$dir/*", und es sollte funktionieren wie du es dir vorstellst. Den Grund kann ich dir allerdings grade nicht erklaeren, da ich A zu faul bin, und B ohne nachzugucken selbst nicht zu 100% sicher bin. ;)

    Ist schon wieder ne Weile her dass ich mir die Details angeguckt hab, vielleicht weiss es ja jemand anders so aussem Kopf.
    <edit>
    Naja, es hat jedenfalls damit zu tun, dass die Zeilenumbrueche vom Output der sub-shell durch Leerzeichen ersetzt werden (weiss nich mehr ob ls oder die Bash das macht).
    Eventuell verstehen neuere Bash Versionen sogar "`ls -A $dir`". "*" wird jedenfalls immer korrekt expandiert.
    </edit>

    Und bei Verzeichnissen mit Leerzeichen beachten was ar0 schon schrieb.

    mfg,
    bytepool
     
  12. ar0

    ar0 Jungspund

    Dabei seit:
    29.03.2010
    Beiträge:
    17
    Zustimmungen:
    0
    @bytepool: du darfst den Asterisk nicht quoten, sonst wird er nicht expandiert. Außerdem bekommt man so keine versteckten Dateien, falls die Option dotglob nicht gesetzt ist: (die afaik per default deaktiviert ist)
    Code:
    set -o
    [...]
                  dotglob If set, bash includes filenames beginning with a ‘.’ in the results of pathname expansion.
    

    Und zu newlines in command substitution:
    Code:
    $ set|grep IFS
    IFS=$' \t\n'
    
    Das ist glaub ich auch der Default-Wert.
     
  13. #12 bytepool, 13.04.2010
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Da muesstest du dich auf eine genaue Shell und Version festlegen, denn das hat bei mir noch in jeder Bash Version funktioniert:
    Code:
    $ for i in "*"; do echo $i; done
    bar.txt bar.txt~ foo.sh foo.sh~ getopts
    
    Funktioniert hier prima mit
    Code:
    $ bash --version
    GNU bash, version 4.1.0(1)-release (i486-pc-linux-gnu)
    $ # und
    $ bash --version
    GNU bash, version 3.2.39(1)-release (i486-pc-linux-gnu)
    $ # und
    $ dpkg -s dash | grep Version
    Version: 0.5.5.1-3
    
    mfg,
    bytepool
     
  14. ar0

    ar0 Jungspund

    Dabei seit:
    29.03.2010
    Beiträge:
    17
    Zustimmungen:
    0
    Das hängt wahrscheinlich davon ab was du unter "funktioniert prima" verstehst.
    Code:
    for i in "*"; do echo "$i"; done
    Wenn du schaun willst wie etwas expandiert wird ist ein herzliches
    Code:
    $ echo "*"
    angebrachter.
     
  15. Anzeige

    Vielleicht findest du HIER Antworten.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  16. #14 bytepool, 13.04.2010
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Tatsaechlich, ich glaube dann verstehe ich zum ersten Mal, wieso 'for i in "*"' tut was es tut. ;)
    D.h. die for-Schleife bekommt tatsaechlich das Sternchen als Argument uebergeben, und die Schleife sorgt dann fuer die korrekte Expansion.

    Trotzdem ist es gerade deswegen allein mit den Quotes korrekt, ansonsten hast du wieder das Leerzeichen Problem.

    Aber danke fuer die Aufklaerung.

    mfg,
    bytepool
     
  17. Morth

    Morth Grünschnabel

    Dabei seit:
    09.04.2010
    Beiträge:
    6
    Zustimmungen:
    0
    sauber, das mit dem expandieren der arrays ist ja cool :)

    aber "while read" hab ich noch nicht voll geschnallt, ich musste mir was basteln, damit es bei mir funktioniert hat.
    aber ich komme der sache schon sehr viel näher, dank euch!

    Code:
    #!/bin/bash
    VERZEICHNISSE=("/var" "/var/tmp")
    
    for dir in "${VERZEICHNISSE[@]}"; do
            lines() {
                    while read line; do
                    echo "$line++++"
                    done
                    }
            ls -1AQ $dir | lines
    done
    
    ohne die funktion und die pipe habe ich es nicht hinbekommen die lines per kommando an while read zu übergeben.

    zu ls -1AQ:
    -1 weil zeilenweise (klar, war ja der Sinn am while read)
    -A damit ich nicht . und .. mitbekomme, aber trotzdem .datei
    -Q alle Zeilen in " ", weil ich festgestellt habe, dass sonst Leerzeichen am Ende einer übergebenen Zeile abgeschnitten werden.
     
Thema:

Mehrere Verzeichnisse nach best. Dateien/Verz. durchsuchen

Die Seite wird geladen...

Mehrere Verzeichnisse nach best. Dateien/Verz. durchsuchen - Ähnliche Themen

  1. mit einem prüfbefehl mehrere verzeichnisse prüfen (z.b ../check_disk -w 1000 -c 2000)

    mit einem prüfbefehl mehrere verzeichnisse prüfen (z.b ../check_disk -w 1000 -c 2000): hallo leute, wie kann ich mit nur einem prüfbefehl mehrere verzeichnisse auf ihre belegung abfragen und dazu noch schwellwerte vergeben ? bis...
  2. Verzeichnisinhalte in mehreren Verzeichnissen kopieren ohne Verzeichnis selbst

    Verzeichnisinhalte in mehreren Verzeichnissen kopieren ohne Verzeichnis selbst: Hallo Forum, ich habe zig Verzeichnisse bspw. mit Namen "01" bis "42" in denen jeweils ca. 20 Dateien vorhanden sind. Wie kann ich es...
  3. In mehreren Unterverzeichnissen nach einem String suchen

    In mehreren Unterverzeichnissen nach einem String suchen: hallo, möchte am besten mit nur einem Befehl nach einem bestimmten String in mehreren Verzeichnissen suchen. 1) grep "String" *.html sucht ja...
  4. [C] aus zwei oder mehreren Verzeichnissen lesen

    [C] aus zwei oder mehreren Verzeichnissen lesen: Hallo Leute Wieder mal melde ich mich wegen etwas wohl ganz triviales. Mein Programm entwickelt sich nun etwas weiter und ich möchte es nun so...
  5. [Gelöst] Suchen und ersetzen mit Hilfe mehrerer Parameter

    [Gelöst] Suchen und ersetzen mit Hilfe mehrerer Parameter: Hallo zusammen, ich bin an einem Punkt angekommen, wo ich nicht mehr weiter komme und hoffe ihr könnt mir weiter helfen. Anbei ein Ausschnitt aus...