Neue ausführbare Datei mit Datensätzen aus einer Datei und Variablen erstellen

A

AnonStar

Jungspund
Hallo erstmal allesamt.
Mein erster Beitrag hier.

Ich habe in letzter Zeit eigentlich nur Batch-Scripte, HTML etc. geschrieben und nie shells.
Möchte aber jetzt ein Problem mit einer Shell lösen.

Ich verwende SuSE Linux 10.2 und habe folgendes Problem:

Ich benötige oft eine ausführbare Datei, die bestimmte Befehle für einen User ausführt.
Diese Datei enthält viele Variablen, die vorher festgelegt werden müssen (und in der Datei festgelegt sind) und für jeden User und Anwendung verschieden sind.
Da ich diese Datei nun mal oft benötige, möchte ich jetzt ein Shell Script schreiben, das per einfacher Benutzerabfrage (read) die Variablen und das Zielverzeichnis abfragt.
Nun soll dieses shell Script folgendes nach der Benutzerabfrage tun:

- Die ersten x Zeilen aus der ausführbaren Datei in eine neue Datei nach $VAR_ZIEL_DIR kopieren, dann statt die Zeile mit Variable (nennen wir sie mal:) VAR_USER=festgelegter_user_in_datei_angegeben eine neue Zeile anlegen mit VAR_USER=$VAR_ABGEFRAGTER_USER.
Dann wieder x Zeilen kopieren, unten an die erstellte Datei anhängen und die Zeile mit der nächsten Variable wieder (nennen wir sie mal VAR_APPLICATION_DATA=/home/applicationxyz) durch den Text VAR_APPLICATION_DATA= und der Variable, die in dem Programm oberhalb durch Benutzereingabe (read) abgefragt worden ist $APPLICATION_DATA ersetzen (bzw. statt der nicht mit kopierten Zeile diese einfügen).
Und diesen Schritt für alle Variablen (5 stk.) wiederholen.

Ich habe nur leider überhaupt keine Ahnung wie ich das jetzt bewerkstelligen soll... mit sed?

Bitte um Hilfe!

MfG
 
Zuletzt bearbeitet:
Jo mit sed geht's mit awk auch, mit bash builtins sollte es auch möglich sein.
 
Das ist schön, dass es mit sed funktioniert.. Aber trotz vieler Tutorials und der man page verstehe ich sed immernoch nicht vollkommen.
Außerdem habe ich kein Tutorial gefunden, dass ein Beispiel hat, indem Zeilen aus einer Datei kopiert werden UND in eine neu erstellte eingefügt werden, geschweige denn Zeilen in neu kopiert werden und zwischendurch noch anderer Text und Variablen hinzugefügt wird und dann weiterhin an die Datei drangehängt wird und diese nicht übrschrieben wird.
Außerdem soll die Datei bei erneutem Ausführen des scripts überschrieben werden (können), wenn man andere Variablen bei den Abfragen eingeben möchte.

Könnte mir jemand bitte ein Beispiel geben und das - wenns geht - so gut wie möglich mit den einzelnen befehlen und parametern erklären? wäre wirklich nett!

Edit: Am besten ein Beispiel mit der einfachsten Lösung, muss also nicht unbedingt sed sein.. Will uach schnell durchblicken können x)

MfG,

The AnonStar
 
Zuletzt bearbeitet:
Soo.. habe das jetzt einfach mal mit echo gelöst (mit echo in datei schreiben).
Habe aber ncoh ein paar probleme.
Ich habe eine Funktion menu. Dort wird via select case abgefragt welcher menüpunkt.
Bei einem Menüpunkt habe ich am Ende folgende Abfrage:

Code:
echo "Einstellungen ueberarbeiten? (j / N)"
                        read RSET
                                if [ "$RSET" == "j" ]
                                then
                                         menu
                                fi

Leider bricht er bei eingabe von "j" nicht ab und leitet zurück zum Menü sondern macht einfach weiter.
Im Anfangsstadium der Datei gings schonmal halb, aber da war folgender Fehler:
Er leitete zum Menü (Menü wird angezeigt) aber das Programm wurde beendet.

Welchen Fehler hab' ich da gemacht? - Wie gesagt, ich bin Anfänger im Shell programmieren.

----

So, 2.:

In mehreren Menüpunkten müssen die gleichen Funktionen mit eingegebenen Variablen ausgeführt werden.
Da ich nicht bei jedem Menüpunkt den gleichen Quelltext einfügen möchte, würde ich gerne zu einer Sprungmarke springen, den Code dort ausführen und wieder zu der Stelle zurückspringen.´Beim Rücksprung müsste die Sprungmarke via Variable erfolgen, damit er zum richtigen Menüpunkt zurück springt. Einfacher wärs, wenn das parallel erledigt werden könnte...

Wie kann ich soetwas verwirklichen?

----

Zum 3. Punkt:

Ich schreibe in eine Datei durch das Script Ports und User, die ich vergebe.
Da Ports nur einmal vergeben werden können, sollte das Script bei einer Port-Eingabe überprüfen, ob der Port bereits verwendet wird.
Die Datei sieht in etwa so aus:

Code:
25015 gs01
24015 gs01
23015 gs01

Vielen Dank schonmal an alle, die mir helfen =)
 
Zuletzt bearbeitet:
Ad 1.:

Stringvergleich in der Shell mit einfachem "=", nicht mit "==", also
Code:
if [ "$RSET" == "j" ]
ändern zu
Code:
if [ "$RSET" = "j" ]
und schauen, ob's hilft ...

Ad 2.:

GOTO ist ziemlich aus der Mode; dafür gibt's Funktionen, auch in der Shell. Der Rücksprung erfolgt dann automatisch wieder direkt an die Aufrufstelle :)

Ad 3.:

Na, wenn die Liste in eine Datei $FILE eingetragen wird, kannst Du ja mit "grep" prüfen, ob der zuletzt eingegebene $PORT schon vergeben ist ...
Code:
grep "^$PORT " "$FILE" >/dev/null && { echo "Port $PORT schon vergeben"; }

HTH, floyd62
 
Hi,

danke für die Antwort!

Zu 1: Klappt immernoch nicht! Er zeigt zwar das Menü an, fordert aber keine Eingabe auf, sondern arbeitet die datei weiterhin ab und führt alle weiteren Befehle unterhalb der Abfrage aus (obwohl er ja zu der menu funktion gesprungen sein muss, da das menu noch mal ausgegeben wird!). Da eventuell mit Marken arbeiten? (siehe 2)

Zu 2: Welche Möglichkeiten gibts denn da? GOTO akzeptiert und kennt meine shell nicht... Der Rücksprung scheint also (siehe 1) bei dem normalen Funktions-Aufruf automatisch zurück zu springen. Das ist gut! Nur im Fall 1 nicht xD.. Wie kann ich das da unterbinden?

Zu 3:

hat gut geklappt mit grep! Danke.. Nun aber ein neues Problem:

Die Portlisten - Datei ist so aufgebaut: (anders als oben..)

Code:
PORT APPLICATION USER
25015 firewall gs01
24015 antivirus gs01
23015 andere_app gs02
.
.
.
Da ich das Script mehrmals laufen lasse für einen User und eine Anwendung um evtl den Port zu ändern, muss folgendes passieren:

Ich habe gelernt durch grep zu überprüfen, ob $USER schon mit $APPLICATION eingetragen ist.
Code:
$EINGETAGEN=`grep -c "$APPLICATION $USER" $FILE`
#grep -c bestimmt die Anzahl und schreibt sie in die Variable $EINGETRAGEN
if ["$EINGETRAGEN" != "0" ] 
# Prüft, ob die Anzahl nicht 0 ist und soll dann die Löschung dieser Zeile(n) ausführen.
then
   DIESE ZEILE AUS $FILE LÖSCHEN
fi

Ich will also, falls der User bereits mit dieser Anwendung eingetragen ist und nur der Prot gewechselt wird, die Zeile löschen, damit der User nicht doppelt mit der Anwendung und 2 verschiedenen Ports in $FILE steht.
Aber wie lösche ich jetzt die Zeile aus $FILE, die grep mir da rausgefischt hat?

Danke schonmal!
 
Zuletzt bearbeitet:
Code:
EINGETAGEN=$(grep -c "$APPLICATION $USER" $FILE)
if ["$EINGETRAGEN" > "0" ]
then
   grep -v "$APPLICATION $USER" $FILE > $FILE 
fi

oder (finde ich persönlich schöner), Du grep'st auf den Fehlercode des letzten Befehls:

Code:
grep "$APPLICATION $USER"  $FILE > /dev/null 2>&1
if [ $? -eq 0 ]
then
grep -v "$APPLICATION $USER" $FILE > $FILE
fi
 
Zuletzt bearbeitet:
Hi,

danke, habs ausprobiert. Aber jetzt löscht er das gesamte $FILE, das heißt auch alle anderen Einträge.. das soll natürlich NICHT so sein! Wie kann ich das einstellen?

BTW was für Arten von Sprungmarken gibts denn nun noch?
MfG
 
Upps, sorry!

Code:
grep -v "$APPLICATION $USER" $FILE >> $FILE


Und zu den Sprungmarken, denke ich, du meinst Funktionen.
Davon ausgehend, dass du die bash benutzt, die Syntax von hier
[function ] name () { command-list; }
 
Zuletzt bearbeitet:
Upps, sorry!

Code:
grep -v "$APPLICATION $USER" $FILE >> $FILE

Das hilft ihm aber auch nicht weiter, da die zu löschenden Zeilen nicht gelöscht werden, sondern die nicht zu löschenden Zeilen nochmal ans Ende der Datei angehängt werden.

Der ursprüngliche Befehl
Code:
grep -v "$APPLICATION $USER" $FILE > $FILE
war schon korrekt. Allerdings führt die Umleitung in $FILE dazu, dass diese Datei zunächst geleert wird. Dann erst wird grep ausgeführt, was zu einer leeren Datei führt. Wir müssen das Ergebnis des grep-Aufrufs in eine zweite Datei zwischenspeichern und die originale Datei durch diese ersetzen. z.B. so:
Code:
grep -v "$APPLICATION $USER" $FILE > $FILE.new
mv $FILE.new $FILE

Zu 2: Welche Möglichkeiten gibts denn da? GOTO akzeptiert und kennt meine shell nicht... Der Rücksprung scheint also (siehe 1) bei dem normalen Funktions-Aufruf automatisch zurück zu springen. Das ist gut! Nur im Fall 1 nicht xD.. Wie kann ich das da unterbinden?

Das kannst du nicht. Du solltest die Menu-Funktion so aufbauen, daß automatisch dahin zurückgesprungen wird, wenn ein bestimmer Programm-Tel abgefertigt ist. Poste doch mal deine menu-Funktion, dann können wir dir besser weiterhelfen.

Gruß,
Philip
 
Zuletzt bearbeitet:
Das hilft ihm aber auch nicht weiter, da die zu löschenden Zeilen nicht gelöscht werden, sondern die nicht zu löschenden Zeilen nochmal ans Ende der Datei angehängt werden.

Du hast völlig recht. Es kann nur über die zweite Datei und den mv gehen.
 
Hi,

Danke an NoXqs, funktioniert jetzt alles!
Danke auch an SkydiverBS, bin auf die Lösungen schon selbst gekommen ;)
Hab das mit grep genauso wie Du.

Habe auch folgendes gelöst:

Code:
echo "Einstellungen ueberarbeiten? (j / N)"
                        read RSET
                                if [ "$RSET" == "j" ]
                                then
                                         CHANGE=1
                                         routine
                                fi

[... jetzt bei der Funktion] 
routine () {
.
.
.
if [ "$CHANGE" == "1" ]
then
   echo "Beende..."
   exit 0
}
routine
fi

Habe das mit menu ganz rausgenommen, da die menu - Funktion beendet ist, bevor die while case schleifenabfrage überhaupt gestartet wird. Außerdem benötige ich die Änderungen erst in Routine.

Hätte ich die if-Abfrage nicht gemacht, dann würde er zum Anfang der routine zurückspringen, alle Daten werden neu eingegeben und alles wird ausgeführt.
Danach würde aber alles nach der Änderungsabfrage erneut ausgeführt. Das unterbinde ich damit.

Habe aber ein neues Problem:

Ich habe 2 Scripts für eine Anwendung. Ein Script ist dafür, dass die $APPLICATION beim Booten startet. Das andere dafür, dass man die $APPLICATION starten, beenden und restarten kann.
Folgendes Problem besteht jetzt aber: Wenn das boot script die $APPLICATION startet, kann ich mit dem normalen Script diese nicht mehr beenden.

Dazu 2 Auszüge.

Aus dem boot Script:

Code:
start)
    if [[ `su $USER -c "screen -ls |grep $NAME"` ]]
       then
       echo "$APP is already running!"
    else
       echo "Starting $DESC: $NAME"
       su $USER -c "cd $DIR; screen -m -d -S app ./$DAEMON $PARAMS"
    fi
    ;;

und aus dem normalen Script:

Code:
status () { # Diese Funktion muss hier "true" sein
   case "$usagetype" in
   root)
    su - $USER -c "screen -ls" | grep [.]$NAME[[:space:]] > /dev/null
   ;;
   nonroot)
    screen -ls | grep [.]$NAME[[:space:]] > /dev/null
   ;;
   esac
}

Aufgefallen sind mir die beiden Zeilen:

BootScript:

Code:
if [[ `su $USER -c "screen -ls |grep $NAME"` ]]

ist anders als die Überprüfung aus dem normalen Script

Code:
su - $USER -c "screen -ls" | grep [.]$NAME[[:space:]] > /dev/null

Ich denke, dass da ein Fehler drin steckt. Aber wie muss das dann anders sein?

MfG,

The AnonStar

P.S.: Nochmal Danke an alle ;)
 
Zuletzt bearbeitet:
Im Bootscript ist es eine Abfrage, ob die $APLLICATION läuft.

Im Startscript ist es nur eine Befehlszeile, keine Überprüfung.
Die Überprüfung in der CASE-Section ist auf $usagetype.
Wenn root dieses script ausführt, wird der Befehl als User $USER ausgeführt, wenn es ein nicht-root user ist, führt dieser die Zeile aus.
Das Ergebnis dieser beiden Befehle wird aber, soweit ich das sehe nicht weiter verarbeitet.
Sie werden ausgeführt und gut ist. Das scheint mir nicht richtig zu sein.
Muss die Ausgabe vielleicht in eine Variable geschrieben werden, um später den status abfragen zu können??
 
Hi,

was genau funktioniert denn dabei nicht? Du sagst, das bootscript funktioniert - die "application" wird gestartet und läuft.
Der Ausschnitt aus dem normalen Script scheint eine Status-Funktion aus einem start-/stop-Script zu sein, welches den bool'schen Zustand zurückgibt (0 / 1 ...).

Deine Status-Funktion sollte daher diesen Rückgabewert ($?) noch in eine entsprechende Meldung umsetzen, z. B.:

Code:
status () { # Diese Funktion muss hier "true" sein
   case "$usagetype" in
   root)
    su - $USER -c "screen -ls" | grep [.]$NAME[[:space:]] > /dev/null
   ;;
   nonroot)
    screen -ls | grep [.]$NAME[[:space:]] > /dev/null
   ;;
   esac
  [b][ $? -eq 0 ] && echo "$NAME running" || echo "$NAME not running"[/b]
}

Aber da ein remark schon besagt, daß die Funktion true zurückgeben sollte, wird diese Rückgabe vermutlich nach dem Aufruf der Funktion an anderer Position des Scriptes weiterverarbeitet.

Eine andere Möglichkeit wäre, die Rückgabe des jeweiligen Befehls mit Hilfe von bool'schen Verknüpfungen direkt auszuwerten:
Code:
su - $USER -c "screen -ls" | grep [.]$NAME[[:space:]] > /dev/null && echo "$NAME running" || echo "$NAME not runnging"

Gruß Daniel
 
Zuletzt bearbeitet:
Hi,

das einfache Problem ist, dass das Bootscript den Server erkennt (also "true" ausgeben würde), das normale Script bei der kopierten Status-Funktion aber NICHT true ausgibt. (Ja, die status funktion wird in der start und stop funktion weiterverarbeitet. Die beiden Funktionen sind hier aber unerheblich, weil status gar nicht erst true ausgibt....)
Und ich weiß nicht, woran es liegt.

MfG
 
Zuletzt bearbeitet:
Hoffe, ich habe das richtig verstanden ... ein Problem ist möglicherweise, daß in der gezeigten "status()"-Funktion die Option '-' beim "su" verwendet wird. Diese führt nämlich dazu, daß das .profile (oder .bash_profile etc.) des $USER-Accounts ausgeführt wird; wenn in diesem Profile jetzt irgendwelche Menüs oder andere Programme aufgerufen werden, müssen diese erste beendet werden, bevor das Start-Skript wieder die Kontrolle erlangt.

Du könntest mal probieren, einfach die Zeile
Code:
su - $USER -c "screen -ls" | grep [.]$NAME[[:space:]]
zu
Code:
su $USER -c "screen -ls" | grep [.]$NAME[[:space:]]
abzuändern.

Wenn das nicht hilft, müssten wir doch wohl mal 'nen Blick darauf werfen, wie der Return-Wert von status() in den start- und stop-Funktionen verwendet wird ...

Noch eine generelle Frage: eigentlich ist es doch üblich, die Start-Skripten so zu schreiben, daß die sowohl im Startup und Shutdown eingebunden als auch direkt zum Starten und Stoppen einer Applikation verwendet werden können ... ist ja im Prinzip derselbe Ablauf. Hast Du da zwingende Gründe, dafür zwei searate Skripten zu erstellen?

@Fallout:

Ich würde empfehlen, statt
Code:
[ $? -eq 0 ] && echo "$NAME running" || echo "$NAME not running"
sowas wie
Code:
RC=$?
[ $RC -eq 0 ] && echo "$NAME running" || echo "$NAME not running"
return $RC
zu schreiben, um den exit status der vorher ausgeführten Kommandos (also im Prinzip den Rückgabewert von "grep") zu sichern und an den Aufrufer weiterzuleiten. Ohne diese Ergänzung hast Du nämlich eine Status-Funktion, die immer garantiert "true" liefert :D

Grüße, Floyd62
 
Hi,

danke für die Hilfe!
Habs gelöst:

Code:
  su $USER -c "cd $DIR; screen -m -d -S app ./$DAEMON $PARAMS"

Im Bootscript war der Fehler.
Habs umgeändert in:
Code:
  su $USER -c "cd $DIR; screen -A -m -d -S $NAME ./$DAEMON $PARAMS"

und schon gehts! Es hat nur $NAME statt "app" hingemusst.. Dass ich das übersehen konnte *kopfschütel*.

@floyd: Eigentlich schon. Aber das eine Script ist irgendwie nicht boot konform.. deswegen musste ich ein anderes mit weniger funktionen nehmen.

Achso.. Ich arbeite schon wieder an einem neuen Script xD

Ich lese einen vollständigen Pfad in eine Variable ein. Zum Beispiel /home/appdir/app_start_script

nun möchte ich die Variable verarbeiten:

Code:
 sh $VAR start

Hab auch schon mit "" versucht.. geht nicht.
Im Gegensatz zu:
Code:
sh /home/appdir/app_start_script start

funktioniert sofort.
Wie kann ich das aber über eine Variable machen?

MfG
 
Zuletzt bearbeitet:
Hab auch schon mit "" versucht.. geht nicht.

Gibt sh eine Fehlermeldung aus? Ich habs mal kurz getestet, bei mir gehts.

Füge doch mal vor dem
Code:
sh $VAR start
ein
Code:
echo $VAR
ein. Nur zum Testen, ob die Variable existiert und einen Inhalt hat.

Gruß,
Philip
 

Ähnliche Themen

Queue für copy Script

Doppelte Dateien löschen.

Variablen aus Config-Datei auslesen

Zeilenweise auslesen und in Variable speichern / übergeben

Hardlink von Dateien erstellen, Pfadangabe aus TXT

Zurück
Oben