Shellprogrammierung - Übergabe eines Dateidescriptors an ein Script
Shellprogrammierung - Übergabe eines Dateidescriptors an ein Script
Hallo,
zum Hintergund bitte ich, das mal durchzulesen
http://debianforum.de/forum/viewtopic.php?f=29&t=148074
Ich wende mich also an die Experten hier mit meiner Frage: Was mache ich bei der Übergabe der Datei an das Script falsch? Oder gehe ich da von einem prinzipiell falschen Ansatz aus?
zum Hintergund bitte ich, das mal durchzulesen
http://debianforum.de/forum/viewtopic.php?f=29&t=148074
Ich wende mich also an die Experten hier mit meiner Frage: Was mache ich bei der Übergabe der Datei an das Script falsch? Oder gehe ich da von einem prinzipiell falschen Ansatz aus?
Zunächst mal: echo '$@' bewirkt, dass $@ ausgeben wird. Du suchst vermutlich "$@". Und: Wohin sollte das Skript diesen String ausgeben? Skripte öffnen von selbst keine Fenster, das musst du explizit mit xterm -e /bin/echo "$@" o.ä. tun.
Dann willst du keinen Dateidescriptor übergeben, sondern einen Dateinamen. Das ist ein sehr großer Unterschied. Ein Dateidescriptor ist einfach nur eine Zahl, die für einen Ein-/Ausgabekanal in einem Programm steht. Damit willst du normalerweise auf Shell-Ebene nichts zu tun haben, brauchst du für dein Problem auch nicht.
Der Grund für diese Fehlermeldung ist vermutlich, dass dein Skript nicht ausgeführt werden kann. Kannst du es auf der Kommandozeile aufrufen? Wenn ja: Das Sonderzeichen ~ wird nur von Shells ausgewertet, oder das Programm unterstützt es explizit. Gib da bei RapidSVN einen absoluten Pfad an.
Dann willst du keinen Dateidescriptor übergeben, sondern einen Dateinamen. Das ist ein sehr großer Unterschied. Ein Dateidescriptor ist einfach nur eine Zahl, die für einen Ein-/Ausgabekanal in einem Programm steht. Damit willst du normalerweise auf Shell-Ebene nichts zu tun haben, brauchst du für dein Problem auch nicht.
Der Grund für diese Fehlermeldung ist vermutlich, dass dein Skript nicht ausgeführt werden kann. Kannst du es auf der Kommandozeile aufrufen? Wenn ja: Das Sonderzeichen ~ wird nur von Shells ausgewertet, oder das Programm unterstützt es explizit. Gib da bei RapidSVN einen absoluten Pfad an.
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.
Nee, nee, das läuft schon alles in einer Shell, also ich tippe im Terminal ein:
:
RapidSVN startet, ich klicke halt irgendeine Datei an und wähle "Bearbeiten" oder drücke F3. RapidSVN startet das Script, übergibt ihm die Datei (oder eben nicht?), die Fehlermeldung (im selben Terminal) kommt eindeutig vom Script:
Egal, was ich da schreibe, wie gesagt. Ich hab's ja z.B. auch mit $1 probiert (eben das erste übergebene Argument) - dieselbe Fehlermeldung. Offensichtlich wird dort ein Dateideskriptor erwartet, der nicht ankommt.
Also: Ich würde ja gerne mal den Befehl sehen, den RapidSVN da zusammenbastelt. Aus den Einträgen in der ~/.RapidSVN:
(Hierbei steht %1 für die übergebene Datei. Deskriptor, nehme ich an, nicht /pfad/dateiname, oder?)
:
Code: Select all
hk@Melina:~$ rapidsvn
Code: Select all
/home/hk/RapidSVN_prog.sh: Zeile 3: echo: Schreibfehler: Ungültiger Dateideskriptor.
Also: Ich würde ja gerne mal den Befehl sehen, den RapidSVN da zusammenbastelt. Aus den Einträgen in der ~/.RapidSVN:
Code: Select all
[Preferences]
StandardEditor=/home/hk/RapidSVN_prog.sh
AlwaysStandardEditor=1
StandardEditorArgs=%1
Ahaa! Also meldet nicht RapidSVN "ungültiger Dateideskriptor", sondern das Shellskript, genauer das echo. Und das liegt vermutlich daran, dass die Standardausgabe dieses Skriptes nicht offen ist - RapidSVN hat sie zugemacht - du kannst an dieser Stelle nichts ausgeben. Versuche die Ausgabe des echo in eine Datei umzuleiten oder in die Standardfehlerausgabe (mittels >&2), die siehst du ja offensichtlich.wodim wrote:Code: Select all
/home/hk/RapidSVN_prog.sh: Zeile 3: echo: Schreibfehler: Ungültiger Dateideskriptor.
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.
Langsam, langsam, ich bin ja gerade mal fertig mit dem Korrigieren meines letzten Beitrags.Janka wrote:Ahaa! Also meldet nicht RapidSVN "ungültiger Dateideskriptor", sondern das Shellskript, genauer das echo. Und das liegt vermutlich daran, dass die Standardausgabe dieses Skriptes nicht offen ist - RapidSVN hat sie zugemacht - du kannst an dieser Stelle nichts ausgeben. Versuche die Ausgabe des echo in eine Datei umzuleiten.wodim wrote:Code: Select all
/home/hk/RapidSVN_prog.sh: Zeile 3: echo: Schreibfehler: Ungültiger Dateideskriptor.
Also wenn ich das richtig sehe, hat nicht RapidSVN die Standardausgabe für das Script zugemacht, sondern es gab nie eine? (RapidSVN startet das Script, nicht ich. Würde ja zum Testen nichts nützen - wenn ich's aufrufe und ihm meinetwegen /pfad/dateiname als String übergebe, weiß ich, dass "echo $1" das ausgibt.)
Normalerweise "erben" Kindprozesse alle Filedescriptoren des Vaters zum Zeitpunkt des fork(), auch die Standardausgabe. Es ist eine übliche Maßnahme, diese zwischen fork() und exec() zu schließen oder auf andere Descriptoren umzubiegen, z.B. um mit dem Kind zu kommunizieren.wodim wrote:Also wenn ich das richtig sehe, hat nicht RapidSVN die Standardausgabe für das Script zugemacht, sondern es gab nie eine?
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.
Ähm, ich glaub' ich hab' auch wieder mal Schlafstörungen. Am besten überlegen wir doch mal, was man sich da so zur Laufzeit alles angucken sollte. Da gibt's doch tolle Befehle ...
Hier mal eine meiner "Baustellen", also ein Teil von dem, was ich mir für meine Scripte so aus dem Netz zusammenkopiert und -gebastelt habe (das Problem der Fehlerfreiheit ist ein ebenso interessantes wie ungelöstes in der theoretischen Informatik, hab' ich mal gelesen. Darf mich ja auch seit ein paar Jährchen "Dipl.-Ing. f. Informationstechnik" nennen, manchmal fällt mir das doch wieder ein.) Nutzung auf eigene Verantwortung natürlich, Korrekturen / Verbesserungen dringend erwünscht. Es darf auch gelacht werden.
Hier mal eine meiner "Baustellen", also ein Teil von dem, was ich mir für meine Scripte so aus dem Netz zusammenkopiert und -gebastelt habe (das Problem der Fehlerfreiheit ist ein ebenso interessantes wie ungelöstes in der theoretischen Informatik, hab' ich mal gelesen. Darf mich ja auch seit ein paar Jährchen "Dipl.-Ing. f. Informationstechnik" nennen, manchmal fällt mir das doch wieder ein.) Nutzung auf eigene Verantwortung natürlich, Korrekturen / Verbesserungen dringend erwünscht. Es darf auch gelacht werden.
Code: Select all
# /bash_libs/common
errCancel () { # Abbruch bei Fehler
if [ $1 != 0 ]; then beep -l 200 -f 1200; echo Abbruch mit Fehler $1;
exit $1
fi
}
user_input (){ # Usereingabe (1 Zeichen ohne Enter)
beep; read -n 1 -p "$1" x
echo $x
}
################## Prozesshandling
pid_from_command () { # PID eines laufenden Prozesses aus Komandozeile ermitteln
line=`ps ax | grep "$1" | grep -v 'grep'| grep -v 'S+'`
# Beispiel ohne "| grep -v 'S+'" (erste Zeile wird gebraucht):
# 5658 pts/1 SLs+ 2:31 mplayer http://mp3.webradio.rockantenne.de:80
# 5659 pts/1 S+ 0:03 mplayer http://mp3.webradio.rockantenne.de:80
if [ $? == 0 ]; then
echo $(echo $line | cut -d" " -f1)
else
echo 0 # Prozess nicht gefunden
fi
}
kill_from_command () { # Prozess aus Kommandozeile ermitteln und killen
pid=`pid_from_command $1`
kill $pid
echo $?
}
################## Fensterhandling
wid_from_command () { # Fenster-Id aus Kommandozeile ermitteln
### Achtung: wenn z.B. ps ax "icedove" velangt, dann wmctrl "Icedove" ###
wid=`wmctrl -l -x | grep $1 | cut -d" " -f1`
if [ $wid != '' ]; then
echo $wid
else
echo 0 # Kein Fenster gefunden
fi
}
wid_from_pid () { # Fenster-Id aus Prozess-Id ermitteln
wid=`wmctrl -p -l | grep "$1" | cut -d" " -f1`
if [ $wid != '' ]; then
echo $wid
else
echo 0 # Kein Fenster gefunden
fi
}
recoverWindow () { # Fenster wiederherstellen, $1: Fenster-Id
wmctrl -i -a $1
}
closeWindow () { # Fenster schließen, $1: Fenster-Id
wmctrl -i -c $1
}
closeWindow_wait_for_end () { # Fenster schließen und Warten, bis Prozess beendet
# $1: Fenster-Id, $2: Startkommando
closeWindow $1
while [ $? == 0 ]; do
ps ax | grep $2 | grep -v 'grep'
done
}
################# Dateioperationen
addLine () { # String $1 als Zeile an Datei $2 anhängen
echo $str >> $2; errCancel $?
}
delLine () { # Zeile mit String $1 aus Datei $2 löschen - Achtung: Wenn Datei nicht gefunden, wird sie angelegt!
grep -v $1 $2 > /tmp/tempdatei; errCancel $?
mv /tmp/tempdatei $2; errCancel $?
}
set_date () { # Dateidatum von Datei $1 auf $2 setzen
# Eingabe $2: dd.mm.yy, touch verlangt yymmdd
touch --date=${2:6:2}${2:3:2}${2:0:2} $1
# touch --date=060826 datei
# touch -t 0610140915 datei
}
##################### Strings formatieren
repl_chars () { # In String $1 Zeichen $2 durch $3 ersetzen
echo ${1//$2/$3}
}
date_unformat () { # Eingabe: yyyy*mm*dd
echo ${1:8:2}.${1:5:2}.${1:0:4} # Ausgabe: dd.mm.yyyy
}
Nein.Janka wrote:Zunächst mal: echo '$@' bewirkt, dass $@ ausgeben wird. Du suchst vermutlich "$@"
Code: Select all
echo $@ >&2
Code: Select all
/mnt/data/Geraete/HiFiRack/pre/AmpLog/amp_log.asc
Code: Select all
echo $1 >&2
Mit einem Computer kann man Probleme lösen, die man ohne ihn nicht hätte.
Doch. echo $@ ist etwas anderes als echo '$@', wie anderswo von dir selbst geschrieben, und wieder etwas anderes als echo "$@".wodim wrote:Nein.Janka wrote:Zunächst mal: echo '$@' bewirkt, dass $@ ausgeben wird. Du suchst vermutlich "$@"Code: Select all
echo $@ >&2
$ man bash, Abschnitt QUOTING.
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.
Ja und? Gesucht habe ich lediglich eine Möglichkeit, festzustellen, was da übergeben wird (s. Titel des ganzen Threads hier), und wie das zu handeln ist, damit eben das aufgerufene Programm die übergebene Datei öffnet. Und das war schließlich konkret so zu sehen:Janka wrote:Doch. echo $@ ist etwas anderes als echo '$@', wie anderswo von dir selbst geschrieben, und wieder etwas anderes als echo "$@".wodim wrote:Nein.Janka wrote:Zunächst mal: echo '$@' bewirkt, dass $@ ausgeben wird. Du suchst vermutlich "$@"
Also hab' ich mich für deinen Tipp bedankt: Mein Script hat als Kindprozess keine Standardausgabe, das also mal auf die Standard - Fehlerausgabe umleiten - damit war alles klar. Schon vergessen? Also fang' jetzt bloß nicht an, Krümel zu kacken oder die eckige Wahrheit rund biegen zu wollen, nur um unbedingt "Recht zu behalten". Mit solchen Leuten zu diskutieren ist nämlich absolut sinnbefreit.echo $@ >&2
So sieht mein Script übrigens jetzt aus:
Code: Select all
#!/bin/bash
# . /bash_libs/common
# Programm aus RapidSVN starten, s. Eintrag "Standardeditor" in ~/.RapidSVN
# $1: Übergebene Datei (mit Pfad)
#### echo $1 >&2 ###
case $1 in
*.asc) # LTSpice oder gedit
liste='TRUE LTSpice FALSE gedit'
prog=$(zenity --width=250 --height=190 --title="RapidSVN" --text="Spice-Schaltung bearbeiten mit:" --list --radiolist --column="" --column="" $liste)
if [ $prog == 'LTSpice' ]; then
winpath=${1//'/mnt/data'/'D:'} # /mnt/data ist Wine - Laufwerk D
winpath=${winpath//'/'/'\\'} # Slashs durch doppelte Backslashs ersetzen
wine 'C:\Program Files\LTC\LTspiceIV\scad3.exe' $winpath
elif [ $prog == 'gedit' ]; then
gedit $1
fi
;;
# *.bmp|*.jpg)
*.wav|*.mp*) audacity $1 ;;
*) # alles andere -> Standardeditor
gedit $1
;;
esac
Danke, die Manpages meide ich gewöhnlich zu Gunsten etwas "lebendigerer" (und überwiegend deutschsprachiger) Seiten, wie eben z.B. dieser hier. Als alter Deutscher halt.Janka wrote:$ man bash, Abschnitt QUOTING.
Spätestens jetzt fände ich es also angebracht, die Administration hier mal über das nächste Auftreten des seit mehr als 10 Jahren netzbekanntesten Trolls zu infomieren. Aber vorher sich mal über den:
http://www.politik-sind-wir.de/showthre ... post106357
Last edited by wodim on 03. Mar 2014 1:01, edited 1 time in total.
Mit einem Computer kann man Probleme lösen, die man ohne ihn nicht hätte.
Aber sobald ein Leerzeichen im Pfad oder Dateinamen auftaucht, wird der String da abgehackt. Bei $1, nicht bei $@.wodim wrote:liefert (Beispiel):Code: Select all
echo $@ >&2
Code: Select all
/mnt/data/Geraete/HiFiRack/pre/AmpLog/amp_log.asc
übrigens auch.Code: Select all
echo $1 >&2
Wer hat eine plausible Erklärung dafür?
Mit einem Computer kann man Probleme lösen, die man ohne ihn nicht hätte.
Hm, will ich. Bin beim Forschen Praktisch jedes Programm nimmt den nur bis zum ersten Leerzeichen an. Alles, was danach kommt, wird entweder ignoriert oder als zweites [, drittes, viertes, ...] Argument interpretiert. Das äußert sich z.B. so:Janka wrote:Dann willst du keinen Dateidescriptor übergeben, sondern einen Dateinamen.
Code: Select all
iceweasel /pfad/dat ei name.html
Code: Select all
gedit /pfad/dat ei name.txt
Na, und so weiter ... Meine selbstgebastelten Funktionen erst noch ...
Also wie lässt sich ein Dateiname (oder allgemein ein String mit Leerzeichen) korrekt als ein Argument übergeben? Im Terminal doch ganz einfach:
Code: Select all
gedit '/pfad/dat ei name.txt'
Code: Select all
gedit '$datei'
Wiederum:
Code: Select all
case $@ in
*.asc) anweisung(en) ;;
-
-
-
esac
Mir schwant langsam: Das Ganze lässt sich doch sicher ganz elegant umgehen, wenn man keinen String, sondern einen Dateideskriptor übergibt (wie offenbar RapidSVN meinem Script) - aber wie?
(Aus höheren Sprachen wie C, VB, ... ist mir Analoges geläufig als "Kontext", "Call by Reference", "Pointer" oder wie auch immer. Und irgendwie muss sich das wohl hinter dem geheimnisvollen Argument %1 verstecken - das sehe ich bei RapidSVN auch beileibe nicht zum ersten Mal) ...
Mit einem Computer kann man Probleme lösen, die man ohne ihn nicht hätte.
Solltest du also auf Grund meiner "Kritik" die beleidigte Leberwurst spielen, dann schau' doch mal wieder hier 'rein, wenn du dich ausgetrotzt hast:wodim wrote:Also hab' ich mich für deinen Tipp bedankt: Mein Script hat als Kindprozess keine Standardausgabe, das also mal auf die Standard - Fehlerausgabe umleiten - damit war alles klar. Schon vergessen? Also fang' jetzt bloß nicht an, Krümel zu kacken oder die eckige Wahrheit rund biegen zu wollen, nur um unbedingt "Recht zu behalten". Mit solchen Leuten zu diskutieren ist nämlich absolut sinnbefreit.
http://debianforum.de/forum/viewtopic.p ... 85#p979065
So etwa ist meine naive Vorstellung von einer konstruktiven Diskussion zu verstehen.
Mit einem Computer kann man Probleme lösen, die man ohne ihn nicht hätte.
Fehler passieren mir doch auch dauernd und da bin ich froh, wenn mich jemand auf den Irrtum hinweist. Sonst bleibt der nämlich stehen und der nächste der es liest macht ihn nach.wodim wrote:Also fang' jetzt bloß nicht an, Krümel zu kacken
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.