Anzeige:
Ergebnis 1 bis 9 von 9

Thema: csv parsen und gleich die user anlegen?

  1. #1
    Registrierter Benutzer
    Registriert seit
    15.05.2001
    Beiträge
    88

    csv parsen und gleich die user anlegen?

    Hallo ,

    Ich moechte die User aus einem .csv file auslesen. Irgendein $USER hat die per Tabs
    separiert, allerdings habe ich hier grad eine Blockade:

    Code:
    #!/bin/sh -
    
    if [ -z "$1" ]; then
      echo "usage: `basename $0` \$1"
       exit
    fi
    
    # set a friendly delimiter
    
    D=':'
    
    # use a friendly delimiter
    # remove tab!
    
    sed "s/ /$D/g" $1 | \
    while  read line; do
           awk -F "$D" '{
           echo "useradd -c $1 -d -g $2 -u uid -g gid  -s shell"  # }' | sh
    done <"$1"
    Leider bringt das nicht den gewuenschten Effekt. Ich weiss dass es ein Perl
    Modul gibt, aber das moechte ich vermeiden, weil ich nicht auf jeder Kiste
    erst Perl Module installieren moechte...

    Gruss
    403
    ;)

  2. #2
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    zuerst mal vermisse ich in Deinem useradd den Benutzernamen. Wo steht denn der? Du übergibst ja nur einen Kommentar (-c) und eine GID (-g; das gleich doppelt). Ich nehme an, in "uid" und "gid" stehen dann numerische Werte? Wo kriegst Du die her? Oder sollen alle Benutzer die gleiche UID erhalten? Wäre keine so tolle Idee. Und "shell" wird dann wohl auch durch einen gültigen PFad zu einer real existierenden Shell ersetzt, oder?

    Wieso setzt Du erst den Delimiter von \t auf : um, wenn Du anschließend awk benutzt? Der kann mit Tabs als Feldtrenner von Haus aus prima umgehen:
    Code:
    jan@jack:~/tmp> echo -e "1\t2\t3" | awk ' { print "1 =", $1, "2 =", $2, "3 =", $3 } '
    1 = 1 2 = 2 3 = 3
    Damit würde sich Deine Schleife auch gleich deutlich vereinfachen (nämlich verschwinden):
    Code:
    awk  '{ printf "useradd -c %s -d -g %s -u uid -g gid -s shell\n", $1, $2; }' $1 | sh
    Und es geht sogar ganz ohne awk, weil z. B. read auch direkt Daten aus einer Tab-getrennten Liste aufnehmen kann (die fehlenden Felder solltest Du noch ergänzen):
    Code:
    while read comm gid; do
      useradd -c $comm -d -g $gid -u uid -g gid  -s shell
    done <$1
    Der einzige Grund zum Umsetzen des Feldtrenners wäre IMHO, wenn der Kommentar Leerzeichen enthält (das dürfen dann natürlich nie Tabs sein). Dann ginge das so:
    Code:
    jan@jack:~/tmp> echo -e "1\t2\t3" | sed 's/\t/:/g'
    1:2:3
    jan@jack:~/tmp> echo -e "1\t2\t3" | sed 's/ /:/g'
    1:2:3
    Achtung: der Tab im 2. sed wird so erzeugt, dass nacheinander CTRL-v und TAB gedrückt werden. Wenn Du den Delimiter als Variable einsetzen willst, dann musst Du statt '' doppelte Anführungszeichen nehmen. Auch dann kannst Du übrigens mit einer einfachen read-Schleife arbeiten, Du setzt einfach vor der Schleife die Variable IFS auf den Doppelpunkt.

    Jan

    EDIT: Wenn der Kommentar Leerzeichen enthalten kann, dann muss das Argument für die -c-Option im useradd natürlich in "" oder '' eingeschlossen werden (oder jedes Leerzeichen durch einen \ entwertet werden ;-). Nur so als Ergänzung.
    Geändert von jan61 (21-05-2008 um 19:15 Uhr)

  3. #3
    Registrierter Benutzer
    Registriert seit
    15.05.2001
    Beiträge
    88
    Danke Jan, ich gehe es mal in Ruhe durch und melde mich spaeter.
    ;)

  4. #4
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    was ich erst jetzt gesehen habe: Du hast in Deiner Schleife noch einen Fehler. Du fütterst den sed mit der einzulesenden Datei - ok, übergibst die Ausgabe des sed dann per Pipe an die read-Schleife - auch ok. Aber dann schiebst Du noch mal den Dateiinhalt per Eingabeumleitung in die Schleife ('done <"$1"'), das ist überflüssig und dürfte zu Fehlern führen. Der arme read - was soll er denn nun lesen?

    Jan

  5. #5
    Registrierter Benutzer
    Registriert seit
    15.05.2001
    Beiträge
    88
    Oh mann, so eine schlampige useradd Zeile Im Wesentlichen war wohl einer meiner Fehler auch $1 (File) mit $1 als Argumente der csv Datei (Input) verwechselt zu haben. Dass der sed ueberfluessig ist,
    ist mir natuerlich erst nach dem Posting aufgefallen. :kopftisch

    Vielen Dank nochmal.
    ;)

  6. #6
    Registrierter Benutzer
    Registriert seit
    15.05.2001
    Beiträge
    88
    Hi Jan,


    mit printf hatte ich so meine Probleme um z.B. uid/gid mit %d auszulesen.


    aktuelle Situation sieht jetzt so aus (ohne printf):

    Code:
    ,uname -srm && awk '{split ($0, a, ":"); print  "useradd -c " a[1], "-d " a[2], 
    "-g " a[3], "-u " a[4], "-s " a[5]}' bla && cat bla
    SunOS 5.10 sun4u
    useradd -c Looser -d /home/looser -g 100 -u 24 -s /bin/loosersh
    useradd -c Winner -d /home/winner -g 101 -u 24 -s /bin/sh
    Looser:/home/looser:100:24:/bin/loosersh
    Winner:/home/winner:101:24:/bin/sh
    Leider setzt das voraus, dass die Leute das Format einhalten. Und dass
    awk tab als Standard Delimiter nimmt hab ich inzwischen aus der manpage
    erfahren. Vielen Dank nochmal fuer die Hilfe.

    Gruss
    403
    ;)

  7. #7
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    hm ... hm!

    Syntaktisch verstehe ich eins nicht: Offenbar fütterst Du ja awk nun doch mit ":"-separierten Zeilen. Warum nutzt Du dann nicht die (von Dir ja ursprünglich vorgesehene) -F-Option, um Dir den split im awk zu sparen? Ich hatte ja nur beschrieben, dass es ohne -F geht, wenn man dem awk einfach freie Hand beim Interpretieren des Feld-Delimiters gibt. Mit anderen Feldtrennern ist IMHO die -F-Option immer noch billiger als das manuelle Splitten für jede Zeile.

    Ach ja: Du übergibst dem useradd immer noch keinen Benutzernamen - und dabei ist dies das Einzige, was er wirklich haben will.

    Zitat Zitat von 403 Beitrag anzeigen
    ...Leider setzt das voraus, dass die Leute das Format einhalten.
    *AAAARGH!!!* Nein, niemals, unter keinen Umständen, bei Androhung der Todesstrafe nicht, nur gegen Bestechung in 6-stelliger Höhe (und da muss mindestens eine "9" vorn stehen ;-) darfst Du einer "Leute"-Eingabe vertrauen! Es gibt 3 Regeln beim Verarbeiten von Input:
    1. Vertraue nie einer nicht 150%ig geprüften Eingabe.
    2. Vertraue nie einer nicht 150%ig geprüften Eingabe.
    3. Vertraue nie einer nicht 150%ig geprüften Eingabe.

    Gerade bei einem so heiklen Thema wie dem Anlegen von Benutzern musst Du alles 3fach checken, sonst ist Dein System innerhalb von Sekunden nicht mehr Dein System:
    - es dürfen keine existierenden Benutzer angegeben werden (egal, dass useradd dann rummault - gleich am Eingang einen Riegel vorschieben)
    - warum eine User-ID vorgeben lassen? Das macht das System automatisch. Und das stopft auch gleich ein Sicherheitsloch: Füttert Dich ein "Leut" mit uid 0, dann hast Du einen neuen root-User. Wenn uid's vorgegeben werden müssen (könnte im Zusammenhang mit NFS eine Rolle spielen), dann definierst Du am besten einen zulässigen Bereich, der sicher (unprivilegiert) ist. Alles außerhalb dieses Bereichs wird verschrottet.
    - Gleiches gilt für die GID - der mögliche Schaden ist vielleicht nicht ganz so groß, aber auch heftig (siehe Gruppe root, bin, ...).
    - das Vorgeben der zu benutzenden Shell darfst Du auch nicht dem "Leut" überlassen - was ist, wenn er sich ein SUID-Programm einträgt, mit dem er erweiterte Privilegien erhalten kann?

    Du musst also Deinen awk noch kräftig aufbohren, um die ankommenden Daten halbwegs sicher zu verifizieren. Wenn Du es sauber machst, wird sich mindestens 80% Deines Codes nur um die Prüfung des Inputs drehen. Willkommen im Klub - so sieht das immer aus. Die andere Variante ist: Lass Dir einen Benutzernamen geben, prüfe ihn auf Existenz und mach den Rest selber. Wie gesagt - die ganzen Optionen sind alle optional (wie der Name schon sagt ;-) - das einzige Argument, was useradd immer haben will, ist der Benutzername.

    Jan

  8. #8
    Registrierter Benutzer
    Registriert seit
    15.05.2001
    Beiträge
    88
    moin,

    Vielen Dank fuer den wichtigen Hint! Hatte mich bisher nur auf den awk konzentriert
    Ein Teilproblem ist, das der Sun awk wohl kein space nach -F akzeptiert:

    Code:
    $ awk -F ':' '{print $1}' bla
    awk: syntax error near line 1
    awk: bailing out near line 1
    $ awk -F:  '{print $1}' bla
    Looser
    Winner
    Und ob ich nun mit -F den Delimiter ersetze oder mit split ist mir momentan egal.


    Zum Input: Ich weiss, dass $ADMIN vorher sich die csv Datei ansehen muss, damit meinte ich vor
    allem dass man ja nicht weiss welche legalen n Felder der Kunde dort reinschreibt. illegaler Input
    muss natuerlich weg

    Code:
    bash-3.00# cat bla
    Looser:/home/looser:100:60001:/bin/sh:looser
    Winner:/home/winner:101:60001:/bin/sh:winner
    bash-3.00# awk '{split ($0, a, ":"); print  "useradd -c " a[1], "-d " a[2], "-u " a[3], "-g " a[4], "-s " a[5]," " a[6]}' bla | sh
    bash-3.00# echo $?
    0
    bash-3.00# id looser winner
    Usage: id [-ap] [user]
    bash-3.00# id looser
    uid=100(looser) gid=60001(nobody)
    bash-3.00# id winner
    uid=101(winner) gid=60001(nobody)
    Bitte jetzt kein Gemecker wegen der Gruppe nobody Hab inzwischen eine Testmaschine erkaempft und da darf ich
    jetzt basteln. Was noch optimiert werden muss: Die Pipe an sh sollte nur einmal stattfinden. Und das Einbauen der o.g.
    Checks.

    Gruss 403
    Geändert von 403 (29-05-2008 um 19:56 Uhr) Grund: edit, jetzt wird auch der user angelegt, allerdings fehlen die seccheck
    ;)

  9. #9
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    Zitat Zitat von 403 Beitrag anzeigen
    Ein Teilproblem ist, das der Sun awk wohl kein space nach -F akzeptiert
    Das ist richtig beobachtet (dürfte auf alle Unix-Systeme zutreffen, die keinen GNU-awk haben) - aber das ist ja nicht wirklich ein Problem ;-) Der GNU-awk akzeptiert die Option auch ohne Leerzeichen. Lass es weg, damit bist Du portabel.

    Zitat Zitat von 403 Beitrag anzeigen
    Und ob ich nun mit -F den Delimiter ersetze oder mit split ist mir momentan egal.
    Es war ja nur ein Hinweis, das macht den Code IMHO leichter lesbar und dürfte auch schneller sein, immerhin sparst Du je Zeile eine Funktion ein.

    Zitat Zitat von 403 Beitrag anzeigen
    Bitte jetzt kein Gemecker wegen der Gruppe nobody Hab inzwischen eine Testmaschine erkaempft und da darf ich jetzt basteln.
    Ich mecker ja gar nicht - nobody ist doch ne gute Gruppe - im Gegensatz zu Italowestern zieht die selten schneller ;-)

    Zitat Zitat von 403 Beitrag anzeigen
    Was noch optimiert werden muss: Die Pipe an sh sollte nur einmal stattfinden.
    Die Pipe findet doch nur einmal statt. Alle Ausgaben des awk werden über die eine Pipe an die Shell weitergereicht.

    Ich komme wieder auf meinen Vorschlag zu sprechen, das alles ganz und gar ohne awk und Pipes zu machen (ungetestet):
    Code:
    OLD_IFS="$IFS"
    IFS=":"
    while read comment home uid gid shell user; do
      # Tests
      useradd -c "$comment" -d "$home" -u $uid -g $gid -s $shell $user
    done <bla
    IFS="$OLD_IFS"
    Eine andere Variante wäre, den print, die Pipe und die Shell einfach wegzulassen und im awk den system()-Call zu verwenden. Du musst Dir vor Augen halten, dass Du durch eine Pipe an eine Shell keinen einzigen Prozess einsparst (im Gegenteil, die Pipe und der Shell-Aufruf sind je einer mehr) - der useradd ist nämlich kein Shell-Builtin und wird deshalb sowieso immer per fork() als eigener Prozess aufgerufen.

    Jan

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •