PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : BASH - Script Domains prüfen



mupp
24-01-2008, 10:30
Hallo zusammen,

ich bin dabei mich in Bash Scripte einzulesen und muss sagen für Unix/Linux Anfänger ist das sehr komplex!

Ich möchte eine große Liste von Domains per HTTP-Request prüfen,
es soll dabei eine Ausgabe erfolgen, ob die entsprechende Domain Konnektiert oder nur "geparkt" ist.

Hier mein Script, an dem ich die Verzweiflung bekomme:

#!/bin/bash
VAR1=www.heise.de

DIG=dig $VAR1 | grep -A 1 AUTH
$DIG
echo "$DIG"
if wget $VAR1 2>&1 | grep -q 'Host nicht gefunden' ; then
echo "Anfrage auf $VAR1 war nicht erfolgreich!"
else
echo "Anfrage auf $VAR1 war erfolgreich!"
fi

Die Domain wurde von mir geändert.

jan61
24-01-2008, 19:44
Moin,


...Hier mein Script, an dem ich die Verzweiflung bekomme:...

Ich versehe mal das Script mit Kommentaren:
#!/bin/bash
VAR1=www.heise.de # ok, Du willst diese Domain pruefen

DIG=dig $VAR1 | grep -A 1 AUTH # was willst Du erhalten?
# Folgendes liefert die Befehlsliste "dig $VAR1 | grep -A 1 AUTH":
# ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
#
# Wenn Du diese Ausgabe in die Variable DIG schreiben willst, dann so:
DIG="`dig $VAR1 | grep -A 1 AUTH`"
# allerdings ist mir nicht klar, was Du mit "-A 1" im grep bezweckst.
# da steht nur ne Leerzeile nach der Trefferzeile
$DIG # huch? Du willst das, was in $DIG steht, ausfuehren???
# Das gibt Mecker vom Meister ;-)
echo "$DIG" # ok, mal ausgeben, was in $DIG steht
# die naechste Zeile sieht erstmal ok aus, ich würde aber fuer wget
# noch die Option -q reinnehmen, den eigentlichen Output willst Du
# ja nicht haben. Und bei der Abfrage auf eine Zeichenkette ist Vorsicht
# angebracht - was ist, wenn ein Benutzer Englisch als Sprache einstellt?
if wget $VAR1 2>&1 | grep -q 'Host nicht gefunden' ; then
echo "Anfrage auf $VAR1 war nicht erfolgreich!"
else
echo "Anfrage auf $VAR1 war erfolgreich!"
fiSo, jetzt berichtige mich bitte und erkläre mal, was Du an den Stellen bezweckst, die mir schleierhaft sind.

Jan

mupp
25-01-2008, 10:47
Hallo Jan,

erstmal danke für deine Hilfe! :)

Ich möchte drei Dinge mit dem Script tun:
1) Ich habe ein Textfile mit "X" Domains, die ich im Script Zeile für Zeile verarbeiten möchte
2) Außerdem soll der http-get Request auf Code "200" geprüft werden
3) Ich möchte sehen welche Domain geprüft wird, damit Tipp-Fehler im Textfile mit den genannten Domains vermieden werden kann.

Vielleicht kannst du mir helfen, also vorweg - ich will das Scripten selber lernen und suche kein fertiges!

jan61
25-01-2008, 20:02
Moin,


...Ich möchte drei Dinge mit dem Script tun:
1) Ich habe ein Textfile mit "X" Domains, die ich im Script Zeile für Zeile verarbeiten möchte
2) Außerdem soll der http-get Request auf Code "200" geprüft werden
3) Ich möchte sehen welche Domain geprüft wird, damit Tipp-Fehler im Textfile mit den genannten Domains vermieden werden kann.

Vielleicht kannst du mir helfen, also vorweg - ich will das Scripten selber lernen und suche kein fertiges!

OK, dann nur ein paar Hinweise ;-)
1. Zum zeilenweisen Abarbeiten einer Textdatei gibt es verschiedene Möglichkeiten, ein paar gebräuchliche sind:
cat datei | while read zeile; do
...
done
# oder
for zeile in `cat datei`; do
...
done
# oder
while read zeile; do
...
done <dateiAlle Methoden haben ihre Vor- und Nachteile, am besten ausprobieren und ein wenig im bash-Manual stöbern.

2. Das Prüfen, ob eine Domain überhaupt existiert, geht wohl am einfachsten über host und dann dem Auswerten der Antwort (grep):
jan@jack:~/tmp/tst_wget> host www.heise.de
www.heise.de has address 193.99.144.85
jan@jack:~/tmp/tst_wget> host gibtsnicht.heise.de
Host gibtsnicht.heise.de not found: 3(NXDOMAIN)
dig geht natürlich auch, aber da erscheint mir eine Auswertung der Antwort (weil geschwätziger) schwieriger.

Wenn der Host gar nicht gefunden wurde, kann man innerhalb der Schleife mit continue mit der nächsten Zeile weitermachen oder per break aus der Schleife raushüpfen.

Zum Prüfen, ob hinter der Domain tatsächlich eine erreichbare Webseite liegt (ich nehme an, Dich interessiert nur HTTP), kannst Du wie schon probiert wget nehmen. Ich lege Dir die Optionen -S und --spider nahe, mit denen Du - wieder in Zusammenarbeit mit grep - genau die Infos kriegen solltest, die Du brauchst.

3. Das ist einfach - dafür gibts echo.

Außerdem noch meine 2 Standard-Tipps: Wenn Du innerhalb eines Shell-Scripts Fehlersuche treiben willst, dann setze an den Anfang ein "set -x", damit kriegst Du angezeigt, was die Shell wirklich treibt. Und wenn Du Dir mal ein paar Anregungen holen willst, was mit Shell-Scripts so möglich ist, dann ist /etc/init.d eine wahre Fundgrube.

So, viel Spaß beim Scripten, wenn Du nicht weiterkommst, dann melde Dich einfach wieder.

Jan

mupp
30-01-2008, 13:43
Hallo Jan,

ich komme einfach nicht auf eine vernünftige Lösung, dass ganze
Lesen der advanced bash guide bringt nichts, wenn man aus dem
Kopf heraus das script nicht zusammen basteln kann..

Kannst du mir helfen, in dem du auf jeden Fall bitte entsprechende
Kommentare reinschreibst um mich nochmal in die richtige Richtung zu schubsen??

./test.sh www.heise.de


#!/bin/bash

header=`curl -I -s "$1"`
if [ -n "$header" ]; then
echo "Connected"
else
echo "Not Connected"
fi

Soweit verstehe ich das auch alles.. die Domain wird per http request geprüft und liefert mir connected aus..
Aber wie kann ich das machen, dass ich nicht die Domain dem Script mit gebe, sondern auf eine Datei verweise,
in dem tausend andere stehen??

Ich möchte in der Shell auch sehen welche Domain er gerade prüft..

Kannst du mir nochmal helfen??

jan61
30-01-2008, 22:49
Moin,


......Aber wie kann ich das machen, dass ich nicht die Domain dem Script mit gebe, sondern auf eine Datei verweise,
in dem tausend andere stehen??

Ich machs mal so, dass ich eine Variante zeige, wie man sowas angeht. Du siehst wohl am schnellsten, wie es zu machen ist, wenn Du ein konkretes Beispiel hast.
#!/bin/bash
# Aufruf: check_connect.sh Dateiname

# zuerst pruefen, ob eine Datei uebergeben wurde und ob diese existiert:
# Wichtig: den Variablennamen in "" stellen, er kann Leerzeichen u. a.
# enthalten oder leer sein
if test -z "$1" -o ! -f "$1" -o ! -r "$1"; then
echo "keine Datei angegeben oder nicht existent oder nicht lesbar"
# der naechste echo gibt eine usage-Meldung aus.
# der Ausdruck basename "$0" liefert den Dateinamen des Scripts
# ohne Pfad ($0 ist immer der Scriptname mit Pfad)
# die `` lassen die Shell wissen, dass das darin enthaltene Kommando
# ausgefuehrt werden soll und dessen Ausgabe an die Stelle des
# `...`-Abschnitts eingefügt wird. Da ich aussen um die auszugebende
# Zeile "" gesetzt habe, muss ich die inneren "" mit einem \ entwerten.
echo "Aufruf: `basename \"$0\"` Dateiname"
exit 1
fi

# Jetzt die Schleife ueber die Datei in verschiedenen Varianten

# Variante 1: while-Schleife per read, der Dateiinhalt wird per
# Eingabeumleitung in die Schleife "eingespeist"; domain ist die
# Variable, in der der Inhalt der jeweiligen Zeile steht
while read domain; do
# Ausgeben, welche Domain geprüft wird
echo "Prüfe Domain <$domain>"
header=`curl -I -s "$domain"`
if [ -n "$header" ]; then
echo "<$domain> Connected"
else
echo "<$domain> Not Connected"
fi
done <"$1"

# 2. Variante: while-Schleife, die ihre Daten über eine Pipe von einem
# cat erhält:
cat "$1" | while read domain; do
# Ausgeben, welche Domain geprüft wird
echo "Prüfe Domain <$domain>"
header=`curl -I -s "$domain"`
if [ -n "$header" ]; then
echo "<$domain> Connected"
else
echo "<$domain> Not Connected"
fi
done

# 3. Variante: for-Schleife, die ihre Daten über die oben beschriebene
# Methode aus einem `...`-Block erhält
for domain in `cat "$1"`; do
# Ausgeben, welche Domain geprüft wird
echo "Prüfe Domain <$domain>"
header=`curl -I -s "$domain"`
if [ -n "$header" ]; then
echo "<$domain> Connected"
else
echo "<$domain> Not Connected"
fi
done

exit 0Noch einige Anmerkungen zu den Vor- und Nachteilen der 3 Varianten:

1. + 2. können mit Leerzeichen innerhalb der Zeileninhalte umgehen, was Variante 3 so nicht kann (eine Zeile "a b" würde 2 einzelne Durchläufe verursachen), dafür müsste man die Shell-Variable IFS (Input Field Separator) umsetzen.

1. kann nur aus Dateien lesen (die Eingabeumleitung "<" funktioniert nur mit Dateien), während sich 2. + 3. auch für andere Fälle eignen (z. B. eine wilde Kombination aus Shell-Befehlen wie sed, grep, ..., mit der man Dateien und Anderes manipulieren kann, oder für die Bearbeitung von normalen Kommandoausgaben wie ps), also alles, was Ausgaben auf STDOUT schickt.

In Variante 2 läuft die Schleife in einer Subshell ab (die Pipe öffnet sie), damit kann ich Variablen, die ich innerhalb der Schleife verändere, nach der Schleife nicht auswerten, da sie dort nicht bekannt sind.

Jan

Thallez
01-02-2008, 00:12
Ich glaub das Script macht genau das was du willst.
Es ist zwar ein ganz anderer Ansatz aber es funtioniert.



#!/bin/bash
#
# domcheck A Domain Checking Script
# ver:0.1
# description: Checks The Availability of Domains.
#Latest Version http://******

DOMAINS()
{
if [ ! -e ./domains ]
then
touch ./domains
echo
echo 'Write the domains you want to check in the file domains'
echo 'Attention only one domain per line'
echo 'Example: linux.org'
echo ' debian.org'
echo ' linuxfriends.org'
echo
exit 1
else
echo
fi

}

CLEAR()
{
if [ -e ./domaincheck.log ]
then
rm ./domaincheck.log
touch ./domaincheck.log
else
touch ./domaincheck.log
fi
}

CHECK()
{
for name in $(cat ./domains); do
if ping -q -c 1 $name 2>&1 | grep -q ', 0% packet loss';
then
echo "`date` $name reachable" >> ./domaincheck.log
else
echo "`date` $name unreachable" >> ./domaincheck.log
fi
done
}

RESULT()
{
echo "Attention the following domains are unreachable !!!!"
echo
cat ./domaincheck.log | grep unreachable
echo
}

DOMAINS
CLEAR
CHECK
RESULT

jan61
02-02-2008, 00:39
Moin,


Ich glaub das Script macht genau das was du willst.
Es ist zwar ein ganz anderer Ansatz aber es funtioniert.

nein, das tut es nicht! Finger weg davon.

Die Versionsnummer 0.1 sollte man hier IMHO ernst nehmen, das Script ist ziemlich wacklig (und äußerst unübersichtlich - Code Obfuscation durch Weglassen sämtlicher Strukturierung, sprich Einrückung, finde ich persönlich ziemlich Sch...). Ich habe mir den Code-Abschnitt mal in ein Shellscript kopiert und es dann ganz einfach k.o. gehauen - es gibt noch etliche andere Varianten, wie man das Ding in den Orkus schicken kann - siehe unten:
jan@jack:~/tmp/domchk> chmod 755 domcheck.sh
jan@jack:~/tmp/domchk> mkdir domains domaincheck.log
jan@jack:~/tmp/domchk> ./domcheck.sh

rm: Entfernen von „./domaincheck.log“ nicht möglich: Ist ein Verzeichnis
cat: ./domains: Ist ein Verzeichnis
Attention the following domains are unreachable !!!!

cat: ./domaincheck.log: Ist ein Verzeichnis
Was sagt uns das?

1. Die Tests sind äußerst schlampig, ein -e prüft nun mal ausschließlich die Existenz, aber nie den Dateityp ab. Wenn also im Verzeichnis, aus dem heraus man das Script aufruft, zufälligerweise ein Unterverzeichnis "domains" existiert, dann gibts eben einen Fehler. Und wenn z. B. "domains" keine reguläre Datei, sondern eine Named Pipe oder ein Device ist, dann wirds richtig lustig, dann kann ich nämlich das Script von außen ansteuern, es wird ja ungeprüft gelesen und nirgends gequotet. Und es wird nirgends geprüft, ob ich die "domains"-Datei überhaupt lesen und die "domaincheck.log" schreiben darf - ruf das Script mal in / oder /bin oder ... auf.

2. Noch schlimmer - wenn eine Datei namens "domaincheck.log" im aktuellen Verzeichnis existiert, wird die einfach plattgemacht. Was ist, wenn der Anwender die braucht (könnte ja von einem ganz anderen Programm / Script erzeugt worden sein)? Es wird übrigens auch nicht geprüft, ob der touch auf die "domaincheck.log" klargegangen ist - so kannst Du Dir ratzfatz z. B. Daten zerschießen, alles was Du ausgibst, wird in dem Fall nämlich einfach an die Datei angebammelt (wieder ganz einfach nachvollziehbar: Einfach dem aktuellen Verzeichnis die Schreibrechte entziehen - wenn die Datei Schreibrechte hat, wird angehängt).

3. Es wird keinerlei Eingabevalidierung gemacht:
jan@jack:~/tmp/domchk> rmdir domains/
jan@jack:~/tmp/domchk> echo "www heise.de" >domains
jan@jack:~/tmp/domchk> rmdir domaincheck.log/
jan@jack:~/tmp/domchk> ./domcheck.sh

Attention the following domains are unreachable !!!!

Sa Feb 2 00:13:27 CET 2008 www unreachable
Wow - Das Web ist also nicht erreichbar ;-) - Wer hat das Internet kaputt gemacht??? Für eine ungeprüfte Eingabedatei eine for-Schleife zum Lesen einzusetzen ist tödlich! Da besteht nämlich überhaupt keine Chance mehr, die Eingabe zu validieren (es sei dann, man setzt IFS vorher um).

4. Eigentlich wollte mupp eine Anzeige, welche Domain gerade geprüft wird (nämlich um genau solche Eingabefehler erkennen zu können) - das Script macht also nicht so richtig "genau das was du willst".

5. ping nutzt ein anderes Protokoll als wget & Co. - ICMP. Wenn ein ping ein Resultat liefert, heisst das noch lange nicht, dass auch TCP- oder UDP-Pakete ankommen.

6. Nach Synflood-Attacken per ICMP (siehe man ping, Option -f) vor längerer Zeit (such mal nach "icmp synflood" in Google) haben etliche Admins ICMP in ihren Firewalls geblockt - selbst heise.de war einige Zeit per ping nicht ereichbar. Ich bin mir sicher, dass viele Admins das noch nicht wieder rückgängig gemacht haben. Wenn also ein ping nicht durchkommt, heisst das noch lange nicht, dass die Domain (bzw. der Host - eine Domain kann ping gar nicht checken) nicht erreichbar ist.

Jan

P.S.: Wenn Du schon Werbung machst - auf der Firmenwebseite habe ich die "latest version" dieses Scripts nicht gefunden, auch keine andere. Suchen kann man da ja auch nicht.

mupp
04-02-2008, 11:21
Hallo zusammen,


ich schaue mir das Script in Ruhe wenn ich wieder @work bin an;
Trotzdem vielen lieben Dank dafür..

Grüße aus dem echten Karnevals-okult :)

Dennis!

Thallez
04-02-2008, 22:13
P.S.: Wenn Du schon Werbung machst - auf der Firmenwebseite habe ich die "latest version" dieses Scripts nicht gefunden, auch keine andere. Suchen kann man da ja auch nicht.

Ja ja jetzt bekomm ich es von beiden Seiten schlechter Code der von mir stammt und von der Firma, weil ich schlechten Code verbreitet hab der aber nicht represantativ ist für die Arbeit der Firma ist sondern von mir während meiner Ausbildung geschrieben wurde und nur auf den File-Server rumflog.

Deswegen auch der Edit von der Firmen URL.
Sorry hatte nur gedacht er bring euch weiter.

jan61
06-02-2008, 01:34
Moin,


Ja ja jetzt bekomm ich es von beiden Seiten schlechter Code der von mir stammt und von der Firma, weil ich schlechten Code verbreitet hab der aber nicht represantativ ist für die Arbeit der Firma ist sondern von mir während meiner Ausbildung geschrieben wurde und nur auf den File-Server rumflog...

tut mir leid, wenn Du deswegen Ärger hast. Es ist nur so, dass ich mir Scripts, die (augenscheinlich) von einer Firma stammen, sehr genau anschaue (wenn ich die Zeit dazu habe ;-). Mach es in Zukunft so, dass Du für solche Scripts eben keine "offizielle" Referenz angibst - sonst weckst Du falsche Erwartungen ;-)

Und meine Anmerkungen nimmst Du einfach so, wie sie gemeint waren: Als Code-Review, der hilft, in Zukunft diverse Fehler zu vermeiden. Ich habe die Erfahrungen ja auch nicht mit der Muttermilch eingesogen, sondern durch viele ähnliche Diskussionen in Mailing-Listen u. ä und vor allem durch viel Praxis gewonnen.

Jan