ubuntuusers.de

Dateipfade im Array speichern

Status: Gelöst | Ubuntu-Version: Ubuntu GNOME 14.04 (Trusty Tahr)
Antworten |

chpo7234

Anmeldungsdatum:
15. September 2015

Beiträge: 10

Moin moin,

ich habe mich heute zum ersten mal mit der Bash-Programmierung beschäftigt und dementsprechend unerfahren bin ich auch noch..

Mein Teilproblem sieht wie folgt aus: ich möchte mit dem "find"-Befehl nach bestimmten Ordnern suchen. Das hat im ersten Anlauf ganz gut geklappt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
find_omd_paths() {
    echo "Searching for *omd/sites*-paths..."
    cd /

    all_omd_paths=`find -type d -name omd`

    for path in $all_omd_paths
    do
            if [[ $path == *"sites"* ]]; then
                omd_sites_paths+=($path)
            fi
    done
}

So weit, so gut. Nun habe ich allerdings den Hinweis erhalten, dass die Variante so nicht sicher ist:

1
    all_omd_paths=`find -type d -name omd`

Wenn Sonder- oder Leerzeichen auftauchen sollten, denn soll das ganze nicht mehr funktionieren. Ich wurde dementsprechend auf den Ausdruck "-print0" hingewiesen, und zusätzlich auch auf eine while-Schleife mit read. Das habe ich nun versucht:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
cd /
find -type d -name omd | while IFS= read -r path; do
    omd_sites_paths+=$path
    #echo $path
done

for path in ${omd_sites_paths[@]}; do
    echo $path
done

Das Problem ist nun jedoch, dass ich die einzelnen Pfade einfach nicht in ein Array bekomme. Ich habe mich schon halb tod probiert.. 😛 Wenn ich die kommentierte Zeile mit dem echo allerdings auskommentiere, denn werden mir die gefundenen Pfade korrekt dargestellt. Den Hinweis mit "print0" habe ich nun leider ausser acht gelassen. ☹

Hat jemand einen Hinweis, wie ich die Pfade nun in ein Array speichern kann und später weiter verarbeite?

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13175

chpo7234 schrieb:

So weit, so gut. Nun habe ich allerdings den Hinweis erhalten, dass die Variante so nicht sicher ist:

1
    all_omd_paths=`find -type d -name omd`

Wenn Sonder- oder Leerzeichen auftauchen sollten, denn soll das ganze nicht mehr funktionieren.

Genau.

Ich wurde dementsprechend auf den Ausdruck "-print0" hingewiesen, und zusätzlich auch auf eine while-Schleife mit read. Das habe ich nun versucht:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
cd /
find -type d -name omd | while IFS= read -r path; do
    omd_sites_paths+=$path
    #echo $path
done

for path in ${omd_sites_paths[@]}; do
    echo $path
done

Eine andere Variante ist, eine Subshell zu nutzen:

1
find -type d -name omd -exec sh -c 'for d; do echo "dir: $d"; done' -- {} +

Das Problem ist nun jedoch, dass ich die einzelnen Pfade einfach nicht in ein Array bekomme. Ich habe mich schon halb tod probiert.. 😛 Wenn ich die kommentierte Zeile mit dem echo allerdings auskommentiere, denn werden mir die gefundenen Pfade korrekt dargestellt. Den Hinweis mit "print0" habe ich nun leider ausser acht gelassen. ☹

Hat jemand einen Hinweis, wie ich die Pfade nun in ein Array speichern kann und später weiter verarbeite?

Warum musst Du sie denn in einem Array haben? Wie sieht die weitere Verarbeitung aus?

chpo7234

(Themenstarter)

Anmeldungsdatum:
15. September 2015

Beiträge: 10

Moin rklm,

vielen Dank für deine Antwort!

Als erstes möchte ich alle benötigten Pfade, die "omd" beinhalten, aufsuchen. Das habe ich ja schon.

Im nächsten Schritt möchte ich diese Pfade eingrenzen. Ich möchte jene extra sortieren, die einen bestimmten Unterordner namens "sites" beinhalten. Wenn dann mehrere Ordner den Unterordner "sites" beinhalten, soll der Nutzer letztendlich entscheiden können, welchen er davon haben möchte.. Die Pfad-Eingrenzung habe ich mir eigentlich mit String-Splitting vorgestellt... Und die besagte Nutzer-Entscheidung liegt erst mal fernab meines Problems..

Es kann meinetwegen auch ein anderer Datentyp sein, zum Beispiel eine Liste. Hauptsache ist halt, dass ich mit den Pfaden arbeiten kann. ☺

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13175

chpo7234 schrieb:

Als erstes möchte ich alle benötigten Pfade, die "omd" beinhalten, aufsuchen. Das habe ich ja schon.

Nein, denn dafür hast Du das falsche Suchkriterium. Du brauchst "-name '*omd*'".

Im nächsten Schritt möchte ich diese Pfade eingrenzen. Ich möchte jene extra sortieren, die einen bestimmten Unterordner namens "sites" beinhalten.

Das kannst Du in einem Schritt machen:

1
find -type d -name sites -printf '%h\0' | ...

Wenn dann mehrere Ordner den Unterordner "sites" beinhalten, soll der Nutzer letztendlich entscheiden können, welchen er davon haben möchte.. Die Pfad-Eingrenzung habe ich mir eigentlich mit String-Splitting vorgestellt... Und die besagte Nutzer-Entscheidung liegt erst mal fernab meines Problems..

Das könnte man im Prinzip mit select machen.

Es kann meinetwegen auch ein anderer Datentyp sein, zum Beispiel eine Liste. Hauptsache ist halt, dass ich mit den Pfaden arbeiten kann. ☺

Wenn Du das wirklich robust für beliebige Dateinamen hinbekommen willst, kann das in der Shell etwas eklig werden. Wenig getestet:

1
2
3
select dir in $(find -type d -name sites -printf '%h\0' | sed -z 's#'\''#'\''\\'\'''\''#g;s#^.*$#'\''&'\'' #'); do
  echo "auswahl: $dir"
done

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17604

Wohnort: Berlin

Ich verstehe nicht ganz was gesucht wird. Verzeichnisse, mit Namen 'omd' und Namensbestandteil 'sites'?

Oh, wozu cd, und wie immer Backticks!

1
find / -type d -path "*/omd/sites" -execdir ... {} ";"

Was willst Du mit dem Array machen - kannst Du nicht einfach für jeden Fundort das von find aufrufen lassen?

Ist 'sites' direktes Kind von 'omd', darf es auch 'ositest' statt 'sites' heißen, ist sites auch ein Verzeichnis oder darf das eine Datei sein?

chpo7234

(Themenstarter)

Anmeldungsdatum:
15. September 2015

Beiträge: 10

Moin moin,

vielen Dank für eure Antworten!

Ich definiere das Problem noch mal genauer:

Es sollen alle Pfade aufgesucht werden, die "omd" heißen, und dessen direkter Unterordner "sites" ist. In dem Unterordner "sites" gibt es weitere Ordner, die nach "Seiten" benannt sind.

Zum Beispiel: /opt/omd/sites/testsite/ /opt/omd/sites/home/ /opt/omd/sites/mysite/

Wobei diese Ordnerstruktur nicht immer bei /opt/ beginnen muss. Es kann also auch mal sein, dass der Pfad z.B. wie folgt aussieht: /etc/myomd/omd/sites/testsite/

Für mich ist es nun halt wichtig zu wissen, welche Seiten vorhanden sind. Ich möchte diese dem Benutzer anzeigen, und ihn dann fragen, welche er gerne verwenden möchte.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13175

Hast Du meine Lösung mal ausprobiert?

chpo7234

(Themenstarter)

Anmeldungsdatum:
15. September 2015

Beiträge: 10

Moin moin,

ich muss an dieser Stelle leider zugeben, dass ich es aufgegeben habe. Es hat für mich einfach zu lange gedauert, mich in die Sprache einzuarbeiten. Vieles ist mir einfach noch zu unverständlich gewesen.

Tut mir leid, dass ich an dieser Stelle dann doch für unnötigen Aufwand gesorgt habe. ☹

Ich habe es nun mit Python umgesetzt. Einerseits habe ich dafür schon etwas mehr Verständnis und andererseits muss auf den Systemen für mein Vorhaben eh Python vorinstalliert sein.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env python
# coding: utf8
import subprocess
import os
import sys

''' Description:
    This script installs the check-mk-extension.
    It searches for all omd-sites. Afterwards it asks the
    user which site he want to choose. At least it is
    copies files, sets permissions and installs pythons
    PySNMP-module. '''

def find_sites_directory(omd_directories):
    omd_directories = omd_directories.split("\n")
    sites_directory = ""
    for directory in omd_directories:
        if "sites" in directory:
            sites_directory = directory
            break
       
    if sites_directory is not "":
        return sites_directory.split("sites")[0] + "sites"
           
def find_existing_sites(sites_directory):
    sites_directories = list()
    sites_content = os.listdir(sites_directory)
    for item in sites_content:
        if os.path.isdir(sites_directory + "/" + item):
            sites_directories.append(item)
            
    return sites_directories

def choose_a_site(sites):
    if len(sites) is 0:
        print "Sorry, there aren't any sites available.."
        print "Can't install the software.."
    elif len(sites) > 1:
        
        while True:
            site = raw_input("Choose a site: ")
            
            if site in sites:
                return site
            else:
                print "Couldn't find this site..."
                exit_code = raw_input("Type 'x' for exit: ")
                if exit_code is "x":
                    return

def move_files_and_set_permissions(sites_directory, site):
    checkmk_directory = sites_directory + "/" + site + "/etc/check_mk/"
    wato_directory = checkmk_directory + "conf.d/wato"
    www_directory = sites_directory + "/" + site + "/var/www/"
    scan_directory = os.getcwd() + "/scan"
    
    check_directorys(wato_directory, www_directory, scan_directory)
    
    print "Move the scan-directory into the wwww-directory..."
    os.system("sudo mv " + scan_directory + " " + www_directory)
    
    print "Move the multisite.mk-menu into checkmk-directory..."
    #os.system("mv " + os.getcwd() + "/multisite.mk " + checkmk_directory)
    # Vor dem Einsatz auskommentieren!
    #
    print "Set permissions to the following directories: "
    print wato_directory
    print www_directory
    
    os.system("sudo chmod 777 * -R " + wato_directory)
    os.system("sudo chmod 777 * -R " + www_directory)
             
def check_directorys(wato_directory, www_directory, scan_directory):
    if not os.path.isdir(wato_directory):
        sys.exit("Missing the following directory: " + wato_directory)
    elif not os.path.isdir(www_directory):
        sys.exit("Missing the following directory: " + www_directory)
    elif not os.path.isdir(scan_directory):
        sys.exit("Missing the following directory: " + scan_directory)
        
def install_python_modules():
    print "Installing necessary python-modules..."
    os.system("sudo apt-get install python-pip python-dev build-essential")
    os.system("sudo pip install --upgrade pip")
    os.system("sudo pip install pysnmp")
                
def main():
    if not os.getuid() == 0:
        sys.exit("This program needs 'root'")
        
    print "Searching for OMD-directories..."

    omd_directories = subprocess.check_output(["find", "/", "-type", "d", "-name", "omd"])
    
    if not "sites" in omd_directories:
        print "Damn.. Couldn't find any omd-directories.."
        sys.exit("Can't install the software, sorry...")
        
    sites_directory = find_sites_directory(omd_directories)
    sites = find_existing_sites(sites_directory)
    number_of_sites = len(sites)
    
    print "Found " + str(number_of_sites) + " omd-sites: ",
    
    for site in sites:
        print site,
    print ""
        
    site = choose_a_site(sites)
    
    if site is None:
        exit()
    
    move_files_and_set_permissions(sites_directory, site)
    install_python_modules()

if __name__ == '__main__':
    main()
    

Lieben Gruss

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13175

chpo7234 schrieb:

Ich habe es nun mit Python umgesetzt. Einerseits habe ich dafür schon etwas mehr Verständnis und andererseits muss auf den Systemen für mein Vorhaben eh Python vorinstalliert sein.

Ist auf jeden Fall die einfachere Wahl. 👍

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

@chpo7234: Bei Deinem Script ist leider einiges unschön / unpythonisch gelöst. Zum einen gibt es viele Dinge direkt in Python, für die Du os.system verwendest, zum anderen wäre das subprocess-Modul die bessere Wahl.

Eine Sache, die mir auf die schnelle besonders ins Auge stach:

1
if len(sites) is 0:

Das ist falsch codiert und funktioniert nur aufgrund eines Implementierungsdetails in CPython. (Ich müsste das mal in Jython ausprobieren, um zu sehen, ob das damit schon scheitert)

Du willst hier nicht auf Identität sondern Gleichheit testen:

1
if len(sites) == 0:

Edit: Ich habe es mal mit Jython (2.7.0) getestet:

1
2
3
4
5
6
7
>>> len([]) is 0
True
>>> big_collection = list(range(1000))
>>> len(big_collection) is 1000
False
>>> len(big_collection) == 1000
True

Also scheint die selbe Optimierung auch bei Jython zu existieren (oder direkt in der JVM?) - dennoch sollte man sich nicht darauf verlassen, wie das Beispiel mit einer 1000 elementigen Liste schön zeigt 😉

Für einen ausführlichen Review habe ich jetzt keine Zeit. Wenn Du Interesse daran hast, poste ihn doch im Python Forum; da gibt es viele Leute, die so etwas gerne machen ☺

chpo7234

(Themenstarter)

Anmeldungsdatum:
15. September 2015

Beiträge: 10

Recht herzlichen Dank für deine Tipps, Lysander!

Ich muss zugeben, dass mir der Unterschied zwischen "is" und "==" nie wirklich klar war und ich die Auswahl immer ziemlich sporadisch traf.

Du musst mir natürlich keine "Review" bieten, ich werde natürlich selber mal Google benutzen ☺

Ja, das Python-Forum ist auch echt ziemlich stark!

Lieben Gruß

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

chpo7234 schrieb:

Recht herzlichen Dank für deine Tipps, Lysander!

Immer gerne ☺

Ich muss zugeben, dass mir der Unterschied zwischen "is" und "==" nie wirklich klar war und ich die Auswahl immer ziemlich sporadisch traf.

Hier noch mal ein plastischeres Beispiel mit String-Objekten:

1
2
3
4
5
6
7
8
9
>>> original = "UChef"
>>> kopie = original
>>> kopie is original
True
>>> billige_kopie_aus_fernost = "UChef"
>>> original is billige_kopie_aus_fernost
False
>>> original == billige_kopie_aus_fernost
True

Durch die Zuweisung in Zeile 2 wird lediglich an anderer Name (kopie) an dasselbe Objekt gebunden, das Objekt selber bleibt aber gleich! Die Kopie aus China dagegen erstellt ein neues Objekt im Speicher. Dieses ist eben nicht identisch mit dem ersten; allerdings gleicht es der ersten Zeichenkette natürlich logisch.

Dasselbe gilt dann auch für "komplexere" oder eigene Objekte.

Vielleicht verstehst Du nun diese Optimierung für diese Gruppe von Integerwerten - dabei wird tatsächlich immer dasselbe Objekt genommen. Die Berechnung von len oder anderen Funktionen erzeugt aber sprachlogisch neue Objekte, so dass man sich eben nicht darauf verlassen sollte ☺

Antworten |