Discussion:
Bash Script mit mehreren Parametern
(zu alt für eine Antwort)
Detlef Paschke
2021-02-13 19:32:18 UTC
Permalink
Hallo,

ich stelle meine Frage noch einmal hier, weil meine sie in
de.comp.os.unix.linux.misc trotz meiner Begründung eher auf
Missbilligung gestoßen ist.

Ich habe meine Frage bewusst dort gestellt, weil ich kein großer Script
Schreiber bin, mir jede Zeile Code, jedes Komma, Semikolon und jede
Klammer von der es auch noch drei verschiedene gibt, mühsam einzeln
zusammen suchen muss. Für mich ist einfacher Code wichtig, ich möchte
Ihn aber auch verstehen wenn ich ihn benutze.

Folgendes habe ich vor. Ich habe ein kleines Script, welches
verschiedene Hardwaredaten abruft, jeweils in eine Textdatei speichert
und diese dann per FTP versendet. Das Script wird per Cronjob aufgerufen.

Nun hatte ich zunächst vor, da manche Hardwaredaten nicht so oft wie
andere abgerufen werden müssen, dies mit einer Option beim Aufruf des
Script zu machen. Es gibt dann eben zwei Cronjobs, einmal mit und einmal
ohne Option.

Das klappt auch schon ganz gut, hier einmal der entsprechende Bereich.

# Speicherinformation mit dmicecode auslesen
if [ "x$1" = "x-ram" ] || [ "x$1" = "x-all" ]; then # Nur ausführen mit
der Option -ram oder -all.
/usr/sbin/dmidecode -t 17 > /tmp/phpsysinfo/dmidecode.txt
fi
# RAID Status auslesen
if [ "x$1" = "x-raid" ] || [ "x$1" = "x-all" ]; then # Nur ausführen
mit der Option -raid oder -all.
/usr/sbin/megaclisas-status > /tmp/phpsysinfo/raidmegaclisas-status.txt
fi
# S.M.A.R.T. Werte von SAS auslesen
if [ "x$1" = "x-smart" ] || [ "x$1" = "x-all" ]; then # Nur ausführen
mit der Option -smart oder -all.
for d in /dev/sd[a-e]; do
echo -e "$(/usr/sbin/smartctl -a $d)" > /tmp/phpsysinfo/smart$((n++)).txt;
done
# S.M.A.R.T. Werte von MegaRAID auslesen
for d in 13 15 14 16 17; do
echo -e "$(/usr/sbin/smartctl -a -d megaraid,$d /dev/bus/1)" >
/tmp/phpsysinfo/smart$((n++)).txt;
done
fi
# APC USV auslesen
if [ "x$1" = "x-ups" ] || [ "x$1" = "x-all" ]; then # Nur ausführen mit
der Option -ups oder -all.
echo -e "---$(date +'%a, %d %b %Y %X %z %Z')--- Executing: apcaccess
status\n$(/sbin/apcaccess status)" > /tmp/phpsysinfo/apcupsd.txt
fi

Es können so alle Bereiche einzeln angesprochen werden oder aber alle
werden mit der Option -all abgearbeitet.

Und wie es nun mal so ist, hat man einen Schritt geschafft, möchte man
den nächsten in Angriff nehmen.
Was ich noch nicht hinbekommen habe, ist eine Kombination also z.B.
-smart,ram oder -smart -ram als Option.

Soweit ich gefunden habe, komme ich dabei nur mit $1 nicht mehr aus aber
wie nun recht weiter?

Irgend wo lese ich, dass so etwas mit "while getopts" gemacht werden
kann. Wie aber konkret, und ob es in meinem Fall geeignet ist...???

Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblicks" gibt es nur auf
http://www.schabau.dynip.online
Meine "Merkzettel"
http://www.helpdesk.dynip.online
Stefan Wiens
2021-02-13 22:21:45 UTC
Permalink
Post by Detlef Paschke
Nun hatte ich zunächst vor, da manche Hardwaredaten nicht so oft wie
andere abgerufen werden müssen, dies mit einer Option beim Aufruf des
Script zu machen. Es gibt dann eben zwei Cronjobs, einmal mit und einmal
ohne Option.
Das klappt auch schon ganz gut, hier einmal der entsprechende Bereich.
# Speicherinformation mit dmicecode auslesen
if [ "x$1" = "x-ram" ] || [ "x$1" = "x-all" ]; then # Nur ausführen mit
der Option -ram oder -all.
/usr/sbin/dmidecode -t 17 > /tmp/phpsysinfo/dmidecode.txt
fi
[...]
Es können so alle Bereiche einzeln angesprochen werden oder aber alle
werden mit der Option -all abgearbeitet.
Und wie es nun mal so ist, hat man einen Schritt geschafft, möchte man
den nächsten in Angriff nehmen.
Was ich noch nicht hinbekommen habe, ist eine Kombination also z.B.
-smart,ram oder -smart -ram als Option.
Soweit ich gefunden habe, komme ich dabei nur mit $1 nicht mehr aus aber
wie nun recht weiter?
Irgend wo lese ich, dass so etwas mit "while getopts" gemacht werden
kann. Wie aber konkret, und ob es in meinem Fall geeignet ist...???
Anstatt jedesmal $1 auszuwerten, besser am Anfang einmal und dann
entsprechend Flag-Variablen setzen.

Für getopts müsstest du die Aufrufsyntax anpassen (einzelner Buchstabe,
kein Wort).

Ansonsten halt die Argumentliste selbst parsen (mit den Komma-getrennten
Argumenten geht das nicht anders): $1 auswerten, Flags setzen und dann
shift.
--
Stefan
Torsten Berger
2021-02-14 00:45:24 UTC
Permalink
Hallo Detlef,

Am 13.02.21 um 20:32 schrieb Detlef Paschke:

#!/bin/bash

until [ $# -lt 1 ]; do
case $1 in
--help) echo " Hilfetext";
shift;;
-l) mache etwas ...;
shift;;
-s) und noch etwas;
shift;;
all) case $2 in
on) tue etwas für "all on";;
off) tue etwas für "all off";;
shift 2;;
*) tue etwas für "all irgendwas";;
shift;;
esac;;
*) tue etwas für "irgendwas";;
shift;;
esac
done

Das müsste so auf die Schnelle passen. Vielleicht musst Du $1 und $2
noch in "" setzen.
Den Rest füllst Du einfach mit Deinen Schnipseln.

Viel Spaß!

Bye Torsten.
--
PGP public key:
http://pool.sks-keyservers.net/pks/lookup?op=get&search=0x983B7EA7E3FC9051
Helmut Waitzmann
2021-02-14 01:17:05 UTC
Permalink
Post by Detlef Paschke
Folgendes habe ich vor. Ich habe ein kleines Script, welches
verschiedene Hardwaredaten abruft, jeweils in eine Textdatei
speichert und diese dann per FTP versendet. Das Script wird per
Cronjob aufgerufen.
Nun hatte ich zunächst vor, da manche Hardwaredaten nicht so oft
wie andere abgerufen werden müssen, dies mit einer Option beim
Aufruf des Script zu machen. Es gibt dann eben zwei Cronjobs,
einmal mit und einmal ohne Option.
Das klappt auch schon ganz gut, hier einmal der entsprechende
Bereich.
# Speicherinformation mit dmicecode auslesen
if [ "x$1" = "x-ram" ] || [ "x$1" = "x-all" ]; then # Nur ausführen mit
der Option -ram oder -all.
/usr/sbin/dmidecode -t 17 > /tmp/phpsysinfo/dmidecode.txt
fi
Vorbemerkung:  Wenn Du Shell‐Skripte im Usenet zeigen willst,
schreibe sie bitte so, dass die Shell‐Skript‐Zeilen eine Länge von
ungefähr 66 Zeichen nicht überschreiten, damit Du sie nicht an
unpassenden Stellen umbrechen musst und auch Dein Newsreader sie
nicht umbricht. 

Der oben gezeigte Shell‐Skript‐Ausschnitt würde als Shell‐Skript
nicht funktionieren, weil einige Zeilen umbrochen worden sind.  Auch
machst Du damit es Deinen Lesern schwer, den wirklichen Inhalt des
Shell‐Skripts zu erkennen.  Damit sind Missverständnisse
vorprogrammiert (erinnere Dich an Ulli Horlacher: «Das Skript
funktioniert nicht»).
Post by Detlef Paschke
Es können so alle Bereiche einzeln angesprochen werden oder aber
alle werden mit der Option -all abgearbeitet.
Und wie es nun mal so ist, hat man einen Schritt geschafft, möchte
man den nächsten in Angriff nehmen.
Was ich noch nicht hinbekommen habe, ist eine Kombination also z.B.
-smart,ram oder -smart -ram als Option.
Soweit ich gefunden habe, komme ich dabei nur mit $1 nicht mehr aus
aber wie nun recht weiter?
Irgend wo lese ich, dass so etwas mit "while getopts" gemacht
werden kann. Wie aber konkret, und ob es in meinem Fall geeignet
ist...???
«getopts» ist in Deinem Fall eher weniger geeignet:  «getopts» ist
zur Standard‐Optionenverarbeitung gedacht.  Jede Option besteht
dabei aus einem Minuszeichen und einem einzelnen nachfolgenden
Buchstaben. 

Dabei gibt es zwei Arten von Optionen: solche, die einen
Parameter haben, und solche, die keinen Parameter haben. 

Optionen, die keinen Parameter haben, können auch (ohne ihre
Minuszeichen) zusammengeklebt und gemeinsam hinter ein Minuszeichen
gestellt werden.  Ein Beispiel soll das verdeutlichen:  Statt

ls -l -F

kann man auch


ls -lF

schreiben.  «getopts» kommt genau da ins Spiel:  Es erleichtert dem
Shell‐Skript‐Ersteller die Arbeit, indem es die Optionenballung
«-lF» in die Reihung der Optionen «-l» und «-F» umsetzt.  Genau das
ist bei Deinem Skript aber ja nicht der Fall:  Du möchtest nicht,
dass «-smart» in «-s» «-m» «-a» «-r» «-t» umgesetzt wird.  =>
«getopts» ist für Deinen Anwendungsfall nicht geeignet, die
«while»‐Schleife aber schon. 

#!/bin/sh -
opt_ram=false && opt_raid=false && opt_smart=false &&
opt_ups=false && n=0 &&
while ${1+:} false
do
case "$1" in
(-ram) opt_ram=true ; shift
;;
(-raid) opt_raid=true ; shift
;;
(-smart) opt_smart=true ; shift
;;
(-ups) opt_ups=true ; shift
;;
(-all) opt_ram=true ; opt_raid=true
opt_smart=true ; opt_ups=true ; shift
;;
(--) shift ; break
;;
(-help)
{
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help
echo
} >&2
exit 0
;;
(-*)
printf '%s\n' \
"$0"': unbekannte Option '"$1". \
'Probiere die Option -help' >&2
exit 2
;;
(*) break
;;
esac
if "$opt_ram"
then
# Speicherinformation mit dmidecode auslesen
/usr/sbin/dmidecode -t 17 > /tmp/phpsysinfo/dmidecode.txt
fi
if "$opt_raid"
then
# RAID Status auslesen
/usr/sbin/megaclisas-status > \
/tmp/phpsysinfo/raidmegaclisas-status.txt
fi
if "$opt_smart"
then
# S.M.A.R.T. Werte von SAS auslesen
for d in /dev/sd[a-e]
do
/usr/sbin/smartctl -a "$d" > \
/tmp/phpsysinfo/smart"$((n++))".txt
done
# S.M.A.R.T. Werte von MegaRAID auslesen
for d in 13 15 14 16 17
do
/usr/sbin/smartctl -a -d megaraid,"$d" /dev/bus/1 > \
/tmp/phpsysinfo/smart"$((n++))".txt;
done
fi
if "$opt_ups"
then
# APC USV auslesen
{
date \
+'%a, %d %b %Y %X %z %Z--- Executing: apcaccess status'
/sbin/apcaccess status
} > /tmp/phpsysinfo/apcupsd.txt
fi

Die Aneinanderklebung mehrerer Optionen mit Kommata ist nicht
implementiert.  Man kann aber mehrere Optionen getrennt angeben:
«-smart -ram» sollte funktionieren. 
Detlef Paschke
2021-02-14 09:50:25 UTC
Permalink
Am 14.02.2021 um 02:17 schrieb Helmut Waitzmann:

Hallo Helmut,
Post by Helmut Waitzmann
Post by Detlef Paschke
Das klappt auch schon ganz gut, hier einmal der entsprechende
Bereich.
# Speicherinformation mit dmicecode auslesen
if [ "x$1" = "x-ram" ] || [ "x$1" = "x-all" ]; then # Nur ausführen mit
der Option -ram oder -all.
/usr/sbin/dmidecode -t 17 > /tmp/phpsysinfo/dmidecode.txt
fi
Vorbemerkung:  Wenn Du Shell‐Skripte im Usenet zeigen willst,
schreibe sie bitte so, dass die Shell‐Skript‐Zeilen eine Länge von
ungefähr 66 Zeichen nicht überschreiten, damit Du sie nicht an
unpassenden Stellen umbrechen musst und auch Dein Newsreader sie
nicht umbricht. 
Der oben gezeigte Shell‐Skript‐Ausschnitt würde als Shell‐Skript
nicht funktionieren, weil einige Zeilen umbrochen worden sind.  Auch
machst Du damit es Deinen Lesern schwer, den wirklichen Inhalt des
Shell‐Skripts zu erkennen.  Damit sind Missverständnisse
vorprogrammiert (erinnere Dich an Ulli Horlacher: «Das Skript
funktioniert nicht»).
ja Okay, ich werde darauf achten. Mit Copy and Paste eingefügt, die ganz
langen Kommentare hatte ich schon gelöscht aber stimmt schon, der eine
Kommentar hätte auch raus gemusst, dann wäre das Problem gar nicht gewesen.
Post by Helmut Waitzmann
Post by Detlef Paschke
Was ich noch nicht hinbekommen habe, ist eine Kombination also z.B.
-smart,ram oder -smart -ram als Option.
...
Irgend wo lese ich, dass so etwas mit "while getopts" gemacht
werden kann. Wie aber konkret, und ob es in meinem Fall geeignet
ist...???
«getopts» ist in Deinem Fall eher weniger geeignet:  «getopts» ist
zur Standard‐Optionenverarbeitung gedacht.
...
Dabei gibt es zwei Arten von Optionen: solche, die einen
Parameter haben, und solche, die keinen Parameter haben. 
...
ls -l -F
kann man auch
ls -lF
schreiben.
Das kenne ich natürlich mit dem zusammenschreiben von Optionen, das wird
ja auch bei rsync und vielen anderen Anwendungen so gehandhabt. Das ist
mir aber gar nicht wichtig.
Post by Helmut Waitzmann
«getopts» ist für Deinen Anwendungsfall nicht geeignet, die
«while»‐Schleife aber schon.
Das habe ich hier schon mal für eine Abfrage bei einem Backup-Script für
rsync benutzt. Da ging es um die Abfrage _B_ackup oder _R_estore.
Das werde ich jetzt einzeln Zeile für Zeile durchgehen um zu begreifen,
wann, wo, was, und warum gemacht wird.
Das ist mir immer wichtig, auch um meine persönlichen Kommentare
einzufügen und später zu wissen, an welcher Stelle man Veränderungen
vornimmt.
Post by Helmut Waitzmann
Die Aneinanderklebung mehrerer Optionen mit Kommata ist nicht
«-smart -ram» sollte funktionieren.
Das genügt mir so vollends. Man hat die Möglichkeit, einzelne oder
mehrere Optionen gezielt aufzurufen, dass ist mehr, als ich ursprünglich
vor hatte.

Ich Danke Dir erst mal für die ausführliche Vorlage und vor allem für
Deine Mühe diese für einen nicht Script Profi verständlich darzustellen.

Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblicks" gibt es nur auf
http://www.schabau.dynip.online
Meine "Merkzettel"
http://www.helpdesk.dynip.online
Helmut Waitzmann
2021-02-14 16:36:19 UTC
Permalink
Post by Detlef Paschke
Ich Danke Dir erst mal für die ausführliche Vorlage und vor allem
für Deine Mühe diese für einen nicht Script Profi verständlich
darzustellen.
Bei Unklarheiten einfach nachfragen. 
Detlef Paschke
2021-02-15 15:49:13 UTC
Permalink
Am 14.02.2021 um 17:36 schrieb Helmut Waitzmann:

Hallo Helmut,
Post by Helmut Waitzmann
Post by Detlef Paschke
Ich Danke Dir erst mal für die ausführliche Vorlage und vor allem
für Deine Mühe diese für einen nicht Script Profi verständlich
darzustellen.
Bei Unklarheiten einfach nachfragen. 
es hat sich tatsächlich noch eine Frage aufgetan, es geht um diesen Bereich:

(-help)
{
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help
echo
} >&2
exit 0
;;
(-*)
printf '%s\n' \
"$0"': unbekannte Option '"$1". \
'Probiere die Option -help' >&2
exit 2
;;
(*) break
;;

Ich habe das Script soweit zusammen, noch ein paar mehr Optionen
eingebaut (wie man halt so ist) und es läuft nun eine ganze Zeit so wie
es soll.

Ich habe es nun so, dass ohne Option gar nichts passiert. So kann ich
schön, jeden Punkt einzeln ansteuern und auch den ftp Transfer gezielt
ansteuern
Nun hätte ich gern, wenn ich keine Option angebe, den identischen Output
wie bei -help.

Ich habe mal eine ähnliche Sache mit case gemacht, da habe ich B|b) für
eine Backup Auswahl geschrieben, die man mit Groß- oder Kleinbuchstaben
eingeben kann.

Der angelehnte Versuch, in Deinem Vorschlag (*|-help) zu schreiben und
die zwei Zeilen
(*) break
;;
auszukommentieren hat nicht funktioniert.

Das ist doch sicher wieder nur ein doofer Syntaxfehler, irgend eine
Anführung oder eine besondere Klamme?

Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblicks" gibt es nur auf
http://www.schabau.dynip.online
Meine "Merkzettel"
http://www.helpdesk.dynip.online
Stefan Wiens
2021-02-15 20:54:51 UTC
Permalink
Post by Detlef Paschke
Hallo Helmut,
Post by Helmut Waitzmann
Post by Detlef Paschke
Ich Danke Dir erst mal für die ausführliche Vorlage und vor allem
für Deine Mühe diese für einen nicht Script Profi verständlich
darzustellen.
Bei Unklarheiten einfach nachfragen. 
(-help)
{
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help
echo
} >&2
exit 0
;;
(-*)
printf '%s\n' \
"$0"': unbekannte Option '"$1". \
'Probiere die Option -help' >&2
exit 2
;;
(*) break
;;
Ich habe das Script soweit zusammen, noch ein paar mehr Optionen
eingebaut (wie man halt so ist) und es läuft nun eine ganze Zeit so wie
es soll.
Ich habe es nun so, dass ohne Option gar nichts passiert. So kann ich
schön, jeden Punkt einzeln ansteuern und auch den ftp Transfer gezielt
ansteuern
Nun hätte ich gern, wenn ich keine Option angebe, den identischen Output
wie bei -help.
Ich habe mal eine ähnliche Sache mit case gemacht, da habe ich B|b) für
eine Backup Auswahl geschrieben, die man mit Groß- oder Kleinbuchstaben
eingeben kann.
Der angelehnte Versuch, in Deinem Vorschlag (*|-help) zu schreiben und
die zwei Zeilen
(*) break
;;
auszukommentieren hat nicht funktioniert.
Das ist doch sicher wieder nur ein doofer Syntaxfehler, irgend eine
Anführung oder eine besondere Klamme?
Die Ausgabe des Hilfetexts in eine Funktion auslagern (z. B.
print_help () ) und diese sowohl beim Argument -help als auch bei
Abwesenheit von Argumenten bzw. Flags aufrufen.
--
Stefan
Helmut Waitzmann
2021-02-17 05:36:58 UTC
Permalink
Post by Helmut Waitzmann
(-help)
{
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help
echo
} >&2
exit 0
;;
(-*)
printf '%s\n' \
"$0"': unbekannte Option '"$1". \
'Probiere die Option -help' >&2
exit 2
;;
(*) break
;;
Ich habe das Script soweit zusammen, noch ein paar mehr Optionen
eingebaut (wie man halt so ist) und es läuft nun eine ganze Zeit so
wie es soll.
Ich habe es nun so, dass ohne Option gar nichts passiert. So kann
ich schön, jeden Punkt einzeln ansteuern und auch den ftp Transfer
gezielt ansteuern
Nun hätte ich gern, wenn ich keine Option angebe, den identischen
Output wie bei -help.
Dir ist sicher aufgefallen, dass das Skript bisher (außer bei den
Optionen «-all» und «-help») so vorgeht, dass es zuerst alle Optionen
einsammelt:  Zu jeder Option gibt es eine ensprechende
«opt_…»‐Variable.  Die werden alle beim Skript‐Start auf «false»
gesetzt. 

Wenn es eine Option entdeckt hat, setzt es die entsprechende
«opt_…»‐Variable auf «true». 

Die Option «-all» spielt eine Sonderrolle:  Sie hat keine eigene
«opt_all»‐Variable, sondern es werden alle anderen «opt_…»‐Variablen
auf «true» gesetzt. 

Wenn es alle Optionen ermittelt hat, klappert es die opt_…‐Variablen
ab:  Für jede, die auf «true» steht, führt es die entsprechende
Aktion aus: 

case "$1" in
(-ram) opt_ram=true ; shift
;;
(-raid) opt_raid=true ; shift
;;
(-smart) opt_smart=true ; shift
;;
(-ups) opt_ups=true ; shift
;;
(-all) opt_ram=true ; opt_raid=true
opt_smart=true ; opt_ups=true ; shift
;;

Die Option «-help» wird anders verarbeitet:  Da habe ich keine
«opt_help»‐Variable spendiert, sondern lasse sofort den Hilfetext
ausgeben: 

(-help)
{
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help
echo
} >&2
exit 0
;;


Um Deinem Wunsch zu entsprechen, ist es besser, das zu ändern und
auch die Option «-help» wie die anderen Optionen nur eine
«opt_…»‐Variable auf «true» setzen zu lassen: 

(-help) shift ; opt_help=true
;;

Allerdings würde ich dem Skript dann noch eine weitere Option,
«-no-help», spendieren (aber natürlich bleibt das Deine
Entscheidung, ob Du dem folgen willst):  Möglicherweise wirst Du dem
Skript irgendwann mal die Aufrufparameter maschinell zusammenstellen
lassen wollen, mit dem Gedanken, es soll einfach alles tun, was zu
tun ist.  Dann müsstest Du entweder als Aufrufer den Fall, dass
nichts zu tun ist, sonderbehandeln – nämlich davon absehen, das
Skript (ohne Parameter) überhaupt aufzurufen – oder noch eine Option
«-no-help» einführen, die dafür sorgt, dass auch bei einem
Skript‐Aufruf ohne weitere Optionen keine Hilfe ausgegeben wird. 
Diese Option könntest Du dann immer angeben, egal, welche Optionen
sonst noch dazukommen.  Im «case»‐Teil des Skripts käme dann noch
folgender Zweig dazu: 

(-no-help) shift ; opt_help=false
;;

«-help» würde dann Hilfe ein‐ und «-no-help» würde dann Hilfe
ausschalten, und gewinnen würde die Option von beiden, die später in
der Reihenfolge der vom Aufrufer angegebenen Optionen kommt.  Wenn
keine von beiden angegeben ist, wird im Fall, dass keine anderen
Optionen angegeben sind, so verfahren, als wäre «-help» angegeben
worden, mit anderen Optionen außer «-help» so, als wäre «-no-help»
angegeben worden. 

Die «opt_help»‐Variable wäre dann dreiwertig («false»: nein, «true»:
ja, «»: unbestimmt), und man setzt sie beim Skript‐Start im
Gegensatz zu allen anderen «opt_…»‐Variablen auf «». 

Jede andere Option außer «-help» und «-no-help» müsste sie auf
«false» setzen, wenn sie noch leer ist: 

opt_help="${opt_help:-false}"

Dann kann man auch die «-help»‐Aktion einfach vom Zustand der
«opt_help»‐Variablen abhängig machen.  Im Aktionsteil des Skripts
wird die «opt_help»‐Variable abgefragt:

if "${opt_help:-true}"
then
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help no-help
echo
fi

Hilfe wird dann nur ausgegeben, wenn die Variable «opt_help» auf
«true» steht oder noch unbestimmt ist. 

Das ist vielleicht insgesamt die Lösung, die das Skript einerseits
bequem macht (ohne Parameter gibt es Hilfe und nichts weiter) und
andererseits (mit «-no-help») zum allgemeinen
Mach‐alles‐Nötige‐Kommando macht. 

#!/bin/sh -

# Initialierungen:
opt_ram=false && opt_raid=false && opt_smart=false &&
opt_ups=false && opt_help= && n=0 && exit_status=0 &&

# Auszufuehrende Aktionen ermitteln:
while ${1+:} false
do
case "$1" in
(-ram) shift ; opt_ram=true
opt_help="${opt_help:-false}"
;;
(-raid) shift ; opt_raid=true
opt_help="${opt_help:-false}"
;;
(-smart) shift ; opt_smart=true
opt_help="${opt_help:-false}"
;;
(-ups) shift ; opt_ups=true
opt_help="${opt_help:-false}"
;;
(-all) shift ; opt_ram=true ; opt_raid=true
opt_smart=true ; opt_ups=true
opt_help="${opt_help:-false}"
;;
(-help) shift ; opt_help=true
;;
(-no-help) shift ; opt_help=false
;;
(--) shift ; break
;;
(-*)
printf '%s\n' \
"$0"': unbekannte Option '"$1". \
'Probiere die Option -help' >&2
exit 2
;;
(*) break
;;
esac
done &&

# Ermittelte Aktionen ausfuehren:
if "${opt_help:-true}"
then
{
printf '%s: Optionen:\n' "$0" &&
printf ' -%s' ram raid smart ups all help no-help &&
echo
} || exit_status=1
fi &&
if "$opt_ram"
then
# Speicherinformation mit dmidecode auslesen
/usr/sbin/dmidecode -t 17 > /tmp/phpsysinfo/dmidecode.txt ||
exit_status=1
fi &&
if "$opt_raid"
then
# RAID Status auslesen
/usr/sbin/megaclisas-status > \
/tmp/phpsysinfo/raidmegaclisas-status.txt ||
exit_status=1
fi &&
if "$opt_smart"
then
# S.M.A.R.T. Werte von SAS auslesen
for d in /dev/sd[a-e]
do
/usr/sbin/smartctl -a "$d" > \
/tmp/phpsysinfo/smart"$((n++))".txt ||
exit_status=1
done
# S.M.A.R.T. Werte von MegaRAID auslesen
for d in 13 15 14 16 17
do
/usr/sbin/smartctl -a -d megaraid,"$d" /dev/bus/1 > \
/tmp/phpsysinfo/smart"$((n++))".txt ||
exit_status=1
done
fi &&
if "$opt_ups"
then
# APC USV auslesen
{
date \
+'%a, %d %b %Y %X %z %Z--- Executing: apcaccess status'
/sbin/apcaccess status
} > /tmp/phpsysinfo/apcupsd.txt ||
exit_status=1
fi &&
exit "$exit_status"
Detlef Paschke
2021-02-20 13:51:24 UTC
Permalink
Am 17.02.2021 um 06:36 schrieb Helmut Waitzmann:

Hallo Helmut,

ein paar Tage brauchte ich um mich "durchzuwurschteln".
Post by Helmut Waitzmann
Post by Detlef Paschke
Nun hätte ich gern, wenn ich keine Option angebe, den identischen
Output wie bei -help.
Dir ist sicher aufgefallen, dass das Skript bisher (außer bei den
Optionen «-all» und «-help») so vorgeht, dass es zuerst alle Optionen
einsammelt:  Zu jeder Option gibt es eine ensprechende
«opt_…»‐Variable.  Die werden alle beim Skript‐Start auf «false»
gesetzt.
Zu dieser Zeile (# Initialierungen:) gleich eine Frage.
Ich habe sie So interpretiert, dass dort zunächst alle möglichen
Optionen (außer -all) mit ihrer Standard-Einstellung eingetragen werden.
Soweit richtig verstanden?

Ich finde zu n=0 das es ein Dateizähler sein soll aber was macht das jetzt.
Post by Helmut Waitzmann
Um Deinem Wunsch zu entsprechen, ist es besser, das zu ändern und
auch die Option «-help» wie die anderen Optionen nur eine
«opt_…»‐Variable auf «true» setzen zu lassen: 
(-help) shift ; opt_help=true
;;
So habe ich es jetzt gemacht.
Post by Helmut Waitzmann
Allerdings würde ich dem Skript dann noch eine weitere Option,
«-no-help», spendieren ...
(-no-help) shift ; opt_help=false
;;
Habe ich eingebaut, weil ich so beim Bau des Script auch die Hilfe zum
testen gezielt Ein- und Aus-Schalten kann.
Post by Helmut Waitzmann
ja, «»: unbestimmt), und man setzt sie beim Skript‐Start im
Gegensatz zu allen anderen «opt_…»‐Variablen auf «».
Aber warum, wenn ich sie im Standard auf true setze wird sie doch immer
ausgeführt, wenn sie nicht wo anders auf false gesetzt wird.?
Post by Helmut Waitzmann
Jede andere Option außer «-help» und «-no-help» müsste sie auf
«false» setzen, wenn sie noch leer ist: 
opt_help="${opt_help:-false}"
Und da fing es dann langsam an, wo ich nicht mehr mitgekommen bin.
Post by Helmut Waitzmann
Dann kann man auch die «-help»‐Aktion einfach vom Zustand der
«opt_help»‐Variablen abhängig machen.  Im Aktionsteil des Skripts
if "${opt_help:-true}"
then
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help no-help
echo
fi
Wie bei der Auswahl einer der anderen möglichen Optionen auch, nur das
hier eben der Text ausgegeben wird.

Aber warum muss jetzt hier mit ${opt_help:-true} gearbeitet werden?

Ich habe unter jeder anderen Option opt_help=false geschrieben, was so
wie ich es Verstanden habe, opt_help=true aus der Initialisierungs Zeile
umschaltet.
Post by Helmut Waitzmann
Das ist vielleicht insgesamt die Lösung, die das Skript einerseits
bequem macht (ohne Parameter gibt es Hilfe und nichts weiter) und
andererseits (mit «-no-help») zum allgemeinen
Mach‐alles‐Nötige‐Kommando macht. 
#!/bin/sh -
...
Bei mir ist garantiert der Zeilenumbruch wieder falsch, ich schreibe die
Scripte mit Notepad++ und kopiere dort raus.
Ich weiß und finde nicht, wie Ihr das macht.

#!/bin/bash
# Initialierungen: Die möglichen Optionen für das Script außer -all.
# (Alle mit Standard false außer opt_help mit Standard true.)
opt_ipmicfg=false && opt_ram=false && opt_raid=false && opt_smart=false
&& opt_ups=false && opt_send=false && opt_help=true &&
# Auszuführende Aktionen ermitteln
while ${1+:} false
do
case "$1" in
(-ipmicfg) shift ; opt_ipmicfg=true
opt_help=false
;;
(-ram) shift ; opt_ram=true
opt_help=false
;;
(-raid) shift ; opt_raid=true
opt_help=false
;;
(-smart) shift ; opt_smart=true
opt_help=false
;;
(-ups) shift ; opt_ups=true
opt_help=false
;;
(-all) shift ; opt_ipmitool=true && opt_ipmicfg=true &&
opt_ram=true ; opt_raid=true opt_smart=true ; opt_ups=true
opt_help=false
;;
(-send) shift ; opt_send=true
opt_help=false
;;
(-help) shift ; opt_help=true
;;
(-no-help) shift ; opt_help=false
;;
(-*)
printf '%s\n' \
'unbekannte Option '"$1" 'Probiere Sie '"$0"' -help' >&2
exit 2
;;
(*) break
;;
esac
done
# Ermittelte Aktionen ausführen
# Help
if "$opt_help"
then
{
printf '%s: [Optionen]\n' "$0"
printf ' -%s' ipmicfg ram raid smart ups all send help
echo
} >&2
exit 0
fi
if "$opt_ipmicfg"
then
...

So verstehe ich den Ablauf besser und bei Tests funktioniert scheinbar
alles. Oder habe ich einen Grundsätzlichen Fehler gemacht?

Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblicks" gibt es nur auf
http://www.schabau.dynip.online
Meine "Merkzettel"
http://www.helpdesk.dynip.online
Helmut Waitzmann
2021-02-21 06:32:31 UTC
Permalink
Post by Detlef Paschke
Zu dieser Zeile (# Initialierungen:) gleich eine Frage.
Ich habe sie So interpretiert, dass dort zunächst alle möglichen
Optionen (außer -all) mit ihrer Standard-Einstellung eingetragen werden.
Soweit richtig verstanden?
Ja.
Post by Detlef Paschke
Ich finde zu n=0 das es ein Dateizähler sein soll aber was macht das jetzt.
Ich hatte in Deinem Original nur gesehen, dass die Variable «n»
mittels «$((n++))» verwendet und hochgezählt wird, und war zu faul,
extra im POSIX‐Standard nachzulesen, was geschieht, wenn es die
Variable «n» nicht gibt oder ihr Inhalt keine Zahl ist.  Deshalb
habe ich sie sicherheitshalber auf 0 initialisiert. 
Post by Detlef Paschke
Post by Helmut Waitzmann
Um Deinem Wunsch zu entsprechen, ist es besser, das zu ändern und
auch die Option «-help» wie die anderen Optionen nur eine
«opt_…»‐Variable auf «true» setzen zu lassen: 
(-help) shift ; opt_help=true
;;
So habe ich es jetzt gemacht.
Post by Helmut Waitzmann
Allerdings würde ich dem Skript dann noch eine weitere Option,
«-no-help», spendieren ...
(-no-help) shift ; opt_help=false
;;
Habe ich eingebaut, weil ich so beim Bau des Script auch die Hilfe
zum testen gezielt Ein- und Aus-Schalten kann.
Post by Helmut Waitzmann
Die «opt_help»‐Variable wäre dann dreiwertig («false»: nein,
«true»: ja, «»: unbestimmt), und man setzt sie beim Skript‐Start
im Gegensatz zu allen anderen «opt_…»‐Variablen auf «».
Aber warum, wenn ich sie im Standard auf true setze wird sie doch immer
ausgeführt, wenn sie nicht wo anders auf false gesetzt wird.?
Da hast Du völlig recht.  Ich wollte jedoch unterscheiden können, ob
die Variable «opt_help» nur von der Initialisierung her noch auf
«ja» steht, oder, ob es ausdrücklich die Option «-help» gegeben
hat.  Deswegen habe ich für die Initialisierung einen dritten Wert,
«», verwendet, um ihn von «true» unterscheiden zu können. 
Post by Detlef Paschke
Post by Helmut Waitzmann
Jede andere Option außer «-help» und «-no-help» müsste sie auf
«false» setzen, wenn sie noch leer ist: 
opt_help="${opt_help:-false}"
Und da fing es dann langsam an, wo ich nicht mehr mitgekommen bin.
Der Ausdruck «"${opt_help:-false}"» liefert im Fall, dass die
Variable «opt_help» einen nicht‐leeren Inhalt hat, den Inhalt.  Ist
die Variable jedoch leer oder überhaupt nicht vorhanden, liefert er
«false». 

Der Witz dabei:  Steht die Variable noch von der Initialisierung her
auf «», wird sie auf «false» umgestellt, steht sie aber bereits auf
«true», bleibt sie auf «true» stehen. 

Der Unterschied zeigt sich dann, wenn man das Skript beispielsweise
mit den Parametern

-help -smart

aufruft.  Das ist zugegebenermaßen ein etwas seltsamer Wunsch:  Der
Aufrufer möchte sowohl ausdrücklich Hilfe als auch die
S.M.A.R.T‐Daten erhalten.  Den Wunsch wollte ich ihm nicht
vereiteln. 

Deine Fassung gibt dann keine Hilfe aus, weil die Option «-smart»
die Hilfe abschaltet (deinen Text von weiter unten hier herauf
Post by Detlef Paschke
Ich habe unter jeder anderen Option opt_help=false geschrieben, was
so wie ich es Verstanden habe, opt_help=true aus der
Initialisierungs Zeile umschaltet.
Post by Helmut Waitzmann
Dann kann man auch die «-help»‐Aktion einfach vom Zustand der
«opt_help»‐Variablen abhängig machen.  Im Aktionsteil des Skripts
if "${opt_help:-true}"
then
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help no-help
echo
fi
Wie bei der Auswahl einer der anderen möglichen Optionen auch, nur
das hier eben der Text ausgegeben wird.
Genau. 
Post by Detlef Paschke
Aber warum muss jetzt hier mit ${opt_help:-true} gearbeitet werden?
Weil im Fall, dass das Skript ganz ohne Parameter aufgerufen wird,
die Variable «opt_help» von der Initialisierung her immer noch
auf «» steht.  Dann soll Hilfe ausgegeben werden:  Der Ausdruck

${opt_help:-true}

liefert den Wert «true» in den folgenden drei Fällen:  Die Variable
«opt_help» hat den Wert «true», die Variable ist leer, oder die
Variable gibt es nicht. 
Post by Detlef Paschke
Bei mir ist garantiert der Zeilenumbruch wieder falsch, ich
schreibe die Scripte mit Notepad++ und kopiere dort raus.
Ich weiß und finde nicht, wie Ihr das macht.
Da kann ich Dir nicht recht raten, weil ich mit dem Thunderbird in
Verbindung mit copy and paste keine Erfahrung habe.  (Ich nehme den
für mich besten Newsreader aller Zeiten: Gnus auf Emacs.) 

Du müsstest dem Thunderbird jedenfalls beibringen, dass er dabei
keinen automatischen Umbruch vornimmt, und von Hand darauf achten,
dass die Zeilen nicht zu lang werden.  Wenn 72 Zeichen pro Zeile
nicht überschritten werden, ist es in Ordnung.  (Ich orientiere mich
immer an 68 Zeichen, weil dann noch 4 Zeichen zum mehrfachen
Zitieren dazupassen.) 

Möglicherweise weiß jemand im Newsgroup
«de.comm.software.mozilla.mailnews» besser Bescheid, wie man das mit
dem Thunderbird am besten hinbekommt. 
Detlef Paschke
2021-02-21 10:01:48 UTC
Permalink
Am 21.02.2021 um 07:32 schrieb Helmut Waitzmann:

Hallo Helmut,
Post by Helmut Waitzmann
Post by Detlef Paschke
Ich finde zu n=0 das es ein Dateizähler sein soll aber was macht das jetzt.
Ich hatte in Deinem Original nur gesehen, dass die Variable «n»
mittels «$((n++))» verwendet und hochgezählt wird, und war zu faul,
extra im POSIX‐Standard nachzulesen, was geschieht, wenn es die
Variable «n» nicht gibt oder ihr Inhalt keine Zahl ist.  Deshalb
habe ich sie sicherheitshalber auf 0 initialisiert.
Jetzt verstehe ich es.
Als ich den "Zähler" ((n++)) oder wie man es nennt, damals gefunden
habe, war bei einigen Varianten n=0 definiert, bei anderen Varianten
wurde darauf verzichtet.
Bei mir hat alles ohne n=0 funktioniert (0 wird wohl als Standard
angenommen wenn nicht anders definiert?) und so habe ich auf den Eintrag
n=0 verzichtet.
Post by Helmut Waitzmann
Post by Detlef Paschke
Post by Helmut Waitzmann
Jede andere Option außer «-help» und «-no-help» müsste sie auf
«false» setzen, wenn sie noch leer ist: 
opt_help="${opt_help:-false}"
Und da fing es dann langsam an, wo ich nicht mehr mitgekommen bin.
Der Ausdruck «"${opt_help:-false}"» liefert im Fall, dass die
Variable «opt_help» einen nicht‐leeren Inhalt hat, den Inhalt.  Ist
die Variable jedoch leer oder überhaupt nicht vorhanden, liefert er
«false».
Der Witz dabei:  Steht die Variable noch von der Initialisierung her
auf «», wird sie auf «false» umgestellt, steht sie aber bereits auf
«true», bleibt sie auf «true» stehen. 
Der Unterschied zeigt sich dann, wenn man das Skript beispielsweise
mit den Parametern
-help -smart
Mit dieser Erklärung verstehe ich wieder, was diese Zeile macht und
warum Du sie so eingesetzt hast.
Post by Helmut Waitzmann
Post by Detlef Paschke
Post by Helmut Waitzmann
if "${opt_help:-true}"
then
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help no-help
echo
fi
Wie bei der Auswahl einer der anderen möglichen Optionen auch, nur
das hier eben der Text ausgegeben wird.
Genau. 
Post by Detlef Paschke
Aber warum muss jetzt hier mit ${opt_help:-true} gearbeitet werden?
Weil im Fall, dass das Skript ganz ohne Parameter aufgerufen wird,
die Variable «opt_help» von der Initialisierung her immer noch
auf «» steht.  Dann soll Hilfe ausgegeben werden:  Der Ausdruck
${opt_help:-true}
liefert den Wert «true» in den folgenden drei Fällen:  Die Variable
«opt_help» hat den Wert «true», die Variable ist leer, oder die
Variable gibt es nicht.
Mit deiner obigen Erklärung der Zeile «"${opt_help:-false}"» erklärt
sich mir auch warum und wieso sie hier benutzt wird (bzw. hier dann mit
-true).

Jetzt wo ich diese Zeile etwas verstehe, werde ich sie wohl doch
einbauen. Der Aufruf mit -help und einer weiteren Option ist zwar sehr
unwahrscheinlich aber im Fall der Fälle läuft alles sauber durch.

Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblicks" gibt es nur auf
http://www.schabau.dynip.online
Meine "Merkzettel"
http://www.helpdesk.dynip.online
Detlef Paschke
2021-02-21 10:25:19 UTC
Permalink
Post by Helmut Waitzmann
Post by Detlef Paschke
Post by Helmut Waitzmann
if "${opt_help:-true}"
then
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help no-help
echo
fi
Wie bei der Auswahl einer der anderen möglichen Optionen auch, nur
das hier eben der Text ausgegeben wird.
Genau. 
Ich muss mir auch die ganze Geschichte mit printf erst mal durchlesen.
Ich habe es jetzt nur mit Copy and Paste übernommen, das passt mir gar
nicht.
Ich hätte sicher nur echo genommen, ich muss erst mal schauen, was
printf ist und was es macht.

Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblicks" gibt es nur auf
http://www.schabau.dynip.online
Meine "Merkzettel"
http://www.helpdesk.dynip.online
Helmut Waitzmann
2021-02-21 20:03:45 UTC
Permalink
Post by Detlef Paschke
Ich muss mir auch die ganze Geschichte mit printf erst mal durchlesen.
Ich habe es jetzt nur mit Copy and Paste übernommen, das passt mir gar
nicht.
Ich hätte sicher nur echo genommen, ich muss erst mal schauen, was
printf ist und was es macht.
«echo» kommt aus zwei zu einander inkompatiblen Traditionen.  Man
kann also kein «echo» implementieren, das weder alte Skripte aus der
einen noch alte Skripte aus der anderen Tradition bricht. 

Diese Misere zu beenden, ist «printf» angetreten.  Damit lassen sich
beide Traditionen simulieren.  Der POSIX‐Standard hat Informationen
dazu: 

Zu «echo»:

<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#top>,
darin besonders
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16>
und
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_18>. 

Zu «printf»:

<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html#top>,
darin besonders
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html#tag_20_94_18>. 


Kommst Du noch an den Beitrag


Subject: Schick "echo" in den Ruhestand (was: jsonlint decode in
shell)
From: Helmut Waitzmann <***@xoxy.net>
Newsgroups: de.comp.os.unix.shell
Date: Thu, 14 Jan 2021 00:50:32 +0100
Message-ID: <83wnwgwg53.fsf_-***@helmutwaitzmann.news.arcor.de>
References: <rtjvo0$97v$***@gwaiyur.mb-net.net>
<***@helmutwaitzmann.news.arcor.de>
<rtm50f$nmr$***@gwaiyur.mb-net.net>

und seine Folgebeiträge ran? 
Sieghard Schicktanz
2021-02-22 19:27:14 UTC
Permalink
Hallo Helmut,
Post by Helmut Waitzmann
«echo» kommt aus zwei zu einander inkompatiblen Traditionen.  Man
kann also kein «echo» implementieren, das weder alte Skripte aus der
einen noch alte Skripte aus der anderen Tradition bricht. 
Diese Misere zu beenden, ist «printf» angetreten.  Damit lassen sich
beide Traditionen simulieren.  Der POSIX‐Standard hat Informationen
dazu: 
Gehässige Randbemerkung dazu:
Ja, damit lassen sich evtl. beide Traditionen simulieren, aber das, was
eigentlich den Anspruch erfüllen würde, laäßt sich auch mit "printf"
nicht machen: Beide Traditionen zusammenführen.
D.h. ein altes Skript, das aus einer der beiden "Welten" kommt, kann
nicht mit "printf" so angepasst werden, daß es auch in der anderen
korrekt funktioniert. Aber dafür funktioniert es (weil nicht verfügbar)
auf einem dementsprechend alten System wenigstens zuverlässig in _keiner_
der beiden.

(Evtl. könnte man mit viel Aufwand und Akribie und Durchstöbern einer
Menge systemnaher Daten [zur Laufzeit] eine Simulation implementieren,
die das _jeweilige_ Verhalten des originalen "echo" korrekt nachbildet -
aber das wäre dann halt in der jeweilgen _anderen_ "Tradition" doch
wieder in altgewohnter Weise falsch...)
--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
Helmut Waitzmann
2021-02-26 22:37:08 UTC
Permalink
Post by Detlef Paschke
Hallo Helmut,
Post by Helmut Waitzmann
«echo» kommt aus zwei zu einander inkompatiblen Traditionen.  Man
kann also kein «echo» implementieren, das weder alte Skripte aus
der einen noch alte Skripte aus der anderen Tradition bricht. 
Diese Misere zu beenden, ist «printf» angetreten.  Damit lassen
sich beide Traditionen simulieren.  Der POSIX‐Standard hat
Informationen dazu: 
Ja, damit lassen sich evtl. beide Traditionen simulieren, aber das,
was eigentlich den Anspruch erfüllen würde, laäßt sich auch mit
"printf" nicht machen: Beide Traditionen zusammenführen.
D.h. ein altes Skript, das aus einer der beiden "Welten" kommt,
kann nicht mit "printf" so angepasst werden, daß es auch in der
anderen korrekt funktioniert. Aber dafür funktioniert es (weil
nicht verfügbar) auf einem dementsprechend alten System wenigstens
zuverlässig in _keiner_ der beiden.
Korrekt. 

Der Unterschied besteht darin, dass «echo» weder vor noch nach dem
Erscheinen von «printf» kompatibel zu beiden «echo»‐Traditionen sein
kann:  Wer «echo» nimmt, kann weder auf den alten noch auf den neuen
Systemen kompatibel bleiben. 

Wer «printf» nimmt, kriegt wenigstens auf den neuen Systemen
Kompatibilität hin. 

Außerdem hat «printf» im Gegensatz zu «echo» «erzieherische» Wirkung
auf Shell‐Skript‐Ersteller: 

Man muss beim Aufruf ausdrücklich angeben (und sich daher überlegt
haben), ob der «\» eine Sonderbedeutung erhalten soll
(Formatierungsanweisung «%b») oder nicht (Formatierungsanweisung
«%s»).  Bei «echo» sieht man davon nichts.  Da entscheidet die
Implementierung, ob ähnlich wie bei «%b» oder wie bei «%s» verfahren
wird.  Gut, GNU‐«echo» hat die Optionen «-E» und «-e», mit denen man
ähnliches wählen kann, aber bereits die Optionen brechen mindestens
eine von beiden «echo»‐Traditionen. 
j***@schily.net
2021-02-26 23:19:01 UTC
Permalink
Der Unterschied besteht darin, dass «echo» weder vor noch nach dem
Erscheinen von «printf» kompatibel zu beiden «echo»‐Traditionen sein
kann:  Wer «echo» nimmt, kann weder auf den alten noch auf den neuen
Systemen kompatibel bleiben. 
Wer «printf» nimmt, kriegt wenigstens auf den neuen Systemen
Kompatibilität hin. 
Ist das jetzt als Persiflage oder als Wunschdenken zu sehen?

Hier mal zwei Beispiele dazu, was man bei einem POSIX printf(1) erwarten würde:

bosh
$ printf '\x77a\n'
\x77a
$ printf '%b\n' '\000a'
a
$

Ich empfehle Dir das mal zum Spaß mindestens mit ksh, bash und dash
gegenzuchecken...
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Helmut Waitzmann
2021-02-28 13:08:19 UTC
Permalink
Post by j***@schily.net
Der Unterschied besteht darin, dass «echo» weder vor noch nach
dem Erscheinen von «printf» kompatibel zu beiden
«echo»�Traditionen sein kann:  Wer «echo» nimmt, kann
weder auf den alten noch auf den neuen Systemen kompatibel
bleiben. 
Wer «printf» nimmt, kriegt wenigstens auf den neuen Systemen
Kompatibilität hin. 
Ist das jetzt als Persiflage oder als Wunschdenken zu sehen?
Hier mal zwei Beispiele dazu, was man bei einem POSIX printf(1)
bosh
$ printf '\x77a\n'
\x77a
Definiert POSIX die Bedeutung von «\x» in der
Formatierungszeichenkette von «printf»? 

Ich würde mich auf die in
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html#tag_20_94_13>
genannten Escape‐Sequenzen '\\', '\a', '\b', '\f', '\n', '\r', '\t',
'\v' und "\ddd", wobei ddd eine ein‐ bis dreistellige Oktalzahl ist,
beschränken. 
Post by j***@schily.net
$ printf '%b\n' '\000a'
a
Da fehlt entweder in der Ausgabe ein Byte oder es ist nur nicht zu
sehen.  POSIX erwartet als Ausgabe eine Folge von 3 Bytes,
deutlicher zu sehen, wenn man die Ausgabe durch «od» schiebt.  Das
Kommando

printf '%b\n' '\000a' | od -v -A d -t c


sollte die Ausgabe


0000000 \0 a \n
0000003

ergeben. 
Post by j***@schily.net
Ich empfehle Dir das mal zum Spaß mindestens mit ksh, bash und dash
gegenzuchecken...
«ksh» ist bei mir nicht installiert.  Mit «bash» und «dash», sowie
standalone «printf» sieht es auf einem Debian Buster Linux – nicht
gerade für die neusten Fassungen der Utilities bekannt –, jeweils
durch das Kommando

od -v -A d -t c

geschoben (das im folgenden verwendete Kommando «execlp»[1] tut zur
Bibliotheksfunktion «execlp»
(<https://pubs.opengroup.org/onlinepubs/9699919799/functions/execlp.html#top>)
entsprechendes), so aus: 


Das Kommando


(
execlp 'dash' 'dash' '-c' '--' '"$@"' 'dash' \
'printf' '%b\n' '\000a'
)


liefert die Ausgabe


0000000 \0 a \n
0000003


Das Kommando


(
execlp 'dash' 'sh' '-c' '--' '"$@"' 'sh' \
'printf' '%b\n' '\000a'
)


liefert die Ausgabe


0000000 \0 a \n
0000003


Das Kommando


(
execlp 'bash' 'bash' '-c' '--' '"$@"' 'bash' \
'printf' '%b\n' '\000a'
)


liefert die Ausgabe


0000000 \0 a \n
0000003


Das Kommando


(
execlp 'bash' 'sh' '-c' '--' '"$@"' 'sh' \
'printf' '%b\n' '\000a'
)


liefert die Ausgabe


0000000 \0 a \n
0000003


Das Kommando


(
execlp 'printf' \
'printf' '%b\n' '\000a'
)


liefert die Ausgabe


0000000 \0 a \n
0000003


Sehen alle korrekt aus. 


[1] «execlp» kann mit einem shell‐built‐in «exec», bei dem man mit
der Option «-a» den bei der Bibliotheksfunktion «execlp» «arg0»
genannten Parameter angeben kann, als Shell‐Funktion verwirklicht
werden:

execlp()
{
exec bash -c -- '
f="${1?}" && arg0="${2?}" &&
shift 2 &&
command -- exec -a "$arg0" -- "$f" "$@"
' bash "$@"
}
Michael Bäuerle
2021-03-01 10:36:11 UTC
Permalink
Post by j***@schily.net
[...]
bosh
$ printf '\x77a\n'
\x77a
Definiert POSIX die Bedeutung von «\x» in der Formatierungszeichenkette
von «printf»? 
Ich würde mich auf die in
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html#tag_20_94_13>
genannten Escape‐Sequenzen '\\', '\a', '\b', '\f', '\n', '\r', '\t',
'\v' und "\ddd", wobei ddd eine ein‐ bis dreistellige Oktalzahl ist,
beschränken. 
Post by j***@schily.net
$ printf '%b\n' '\000a' a
Da fehlt entweder in der Ausgabe ein Byte oder es ist nur nicht zu
sehen.  POSIX erwartet als Ausgabe eine Folge von 3 Bytes, deutlicher
zu sehen, wenn man die Ausgabe durch «od» schiebt.  Das Kommando
printf '%b\n' '\000a' | od -v -A d -t c
sollte die Ausgabe
0000000 \0 a \n
0000003
ergeben. 
Post by j***@schily.net
Ich empfehle Dir das mal zum Spaß mindestens mit ksh, bash und dash
gegenzuchecken...
«ksh» ist bei mir nicht installiert.  [...]
Tests mit NetBSD 9 und whatshell [1]:

| $ /bin/ksh ~/whatshell.sh
| @(#)PD KSH v5.2.14 99/07/13.2
| $ /bin/ksh
| $ printf '%b\n' '\000a' | od -v -A d -t c
| 0000000 \0 a \n
| 0000003

| $ /bin/sh ~/whatshell.sh
| ash (FreeBSD, Cygwin pre-1.7, Minix 3.1.3 ff)
| $ /bin/sh
| $ printf '%b\n' '\000a' | od -v -A d -t c
| 0000000 \0 a \n
| 0000003

dash aus pkgsrc [2]:

| $ /usr/pkg/bin/dash ~/whatshell.sh
| ash (dash 0.5.5.1 ff)
| $ /usr/pkg/bin/dash
| $ printf '%b\n' '\000a' | od -v -A d -t c
| 0000000 \0 a \n
| 0000003

pbosh aus pkgsrc [3]:

| $ /usr/pkg/bin/pbosh ~/whatshell.sh
| SVR4 Bourne shell (SunOS 5 schily variant, since 2016-08-08, in posix mode)
| $ /usr/pkg/bin/pbosh
| $ printf '%b\n' '\000a' | od -v -A d -t c
| 0000000 \0 a \n
| 0000003


____________
[1] <https://www.in-ulm.de/~mascheck/various/whatshell/>
[2] <https://ftp.netbsd.org/pub/pkgsrc/current/pkgsrc/shells/dash/README.html>
[3] <https://ftp.netbsd.org/pub/pkgsrc/current/pkgsrc/shells/pbosh/README.html>
j***@schily.net
2021-03-01 12:18:36 UTC
Permalink
Post by j***@schily.net
bosh
$ printf '\x77a\n'
\x77a
Definiert POSIX die Bedeutung von «\x» in der
Formatierungszeichenkette von «printf»? 
Nein, und daher darf eine konforme Implementierung das auch nicht expandieren.
Eine zulässige Erweiterung muß so funktionieren, daß kein vom Standard
abweichendes Verhalten entsteht.
Ich würde mich auf die in
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html#tag_20_94_13>
genannten Escape‐Sequenzen '\\', '\a', '\b', '\f', '\n', '\r', '\t',
'\v' und "\ddd", wobei ddd eine ein‐ bis dreistellige Oktalzahl ist,
beschränken. 
Das ist so keine brauchbare Aussage, weil Konformität ja nicht nur bedeutet daß
dokumentierte Escape Sequenzen expandiert werden, sondern auch das keine
weiteren Dinge expandiert werden, bei denen man nicht damit rechnet.
Post by j***@schily.net
$ printf '%b\n' '\000a'
a
Da fehlt entweder in der Ausgabe ein Byte oder es ist nur nicht zu
sehen.  POSIX erwartet als Ausgabe eine Folge von 3 Bytes,
deutlicher zu sehen, wenn man die Ausgabe durch «od» schiebt.  Das
Kommando
Ich habe das angeführt, weil diverse Shells (incl. dash) das Null Byte entweder
nicht exandieren, oder das 'a' danach nicht mehr ausgeben, weil sie den String
z.B. erst expandieren und dann an ein normales printf(3) weiterreichen.
«ksh» ist bei mir nicht installiert.  Mit «bash» und «dash», sowie
standalone «printf» sieht es auf einem Debian Buster Linux – nicht
gerade für die neusten Fassungen der Utilities bekannt –, jeweils
durch das Kommando
Interessant ist schon, daß bash und ksh \x expandieren, das aber in
unterschiedlicher Weise.

Auch interessant ist, daß die meisten installierten dash Versionen im Feld das
Null Byte nicht korrekt expandieren. Ich hatte dieses Problem mal
veröffentlicht, als ich vor 5 Jahren ein konformes printf(1) als Builtin
Kommando für den Bourne Shell entwickelt habe. Der Bug scheint vor einem
knappen Jahr in dash reariert worden sein, damit ist diese Version aber noch
nicht bei Allen Nutzern vor Ort.

Um die Probleme mit der nicht-konformen Expansion von \x in ksh und bash zu
vermeiden, gleichzeitig aber mehr Expansionsmöglichkeiten zu bekommen, werden
wir im nächsten POSIX Standard (ISSUE-8) der vermutlich in einem Jahr kommt,
die Expansion $'...' einführen. Damit wird \uxxxx, \uxxxxxxxx, \xnnnn,
\xnnnnnnnn unterstützt.

Wann das dann in den Shells ankommt, wird sich zeigen. Ich habe für den Bourne
Shell (bosh) entschieden, noch ein paar Monate zu warten, weil aktuell noch
nicht sichergestellt ist, daß sich daran nichts mehr im Einzelnen ändert.

Aktuell gibt es bei dash übrigens folgende mir bekannte Abweichungen vom POSIX
Standard, wobei ich mal die Annahme mache, daß Linux sich als UNIX-kompatibel
bezeichnet und daher alle XSI Erweiterungen aus POSIX für eine POSIX
Konformität implementiert werden müssen:

- Kein Support für multi-byte Zeichen

- "echo '\1'" wird nach ^A expandiert, was verboten ist.
Gefordert ist im Standard "echo '\0001'"

- "printf '%b\n' '\1'" wird expandiert, obwohl das wie bei echo
verboten ist, denn \b soll ja echo Kompatibilität liefern.
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Thomas Dorner
2021-03-01 19:10:30 UTC
Permalink
Hallo Jörg!
Post by j***@schily.net
Post by j***@schily.net
bosh
$ printf '\x77a\n'
\x77a
Definiert POSIX die Bedeutung von "\x" in der
Formatierungszeichenkette von "printf"?
Nein, und daher darf eine konforme Implementierung das auch nicht expandieren.
Eine zulässige Erweiterung muß so funktionieren, daß kein vom Standard
abweichendes Verhalten entsteht.
Wo steht das? Bei %b steht sogar explizit, daß andere Erweiterungen
nicht spezifiziert sind:

| The interpretation of a <backslash> followed by any other sequence of
| characters is unspecified.

IMHO darf bei "\x" in printf jede Shell machen, was sie will.

Viele Grüße, Thomas

PS: Natürlich ist ein Skript, daß das benutzt, danach nicht mehr
portabel.
--
Adresse gilt nur kurzzeitig!
j***@schily.net
2021-03-01 20:32:57 UTC
Permalink
Wo steht das? Bei %b steht sogar explizit, daß andere Erweiterungen
| The interpretation of a <backslash> followed by any other sequence of
| characters is unspecified.
IMHO darf bei "\x" in printf jede Shell machen, was sie will.
...
PS: Natürlich ist ein Skript, daß das benutzt, danach nicht mehr
portabel.
Für Skripte, die nur vorgefertigte Strings verarbeiten, mag das stimmen.

Für Skripte, die Strings nie expandieren wollen und daher %s verwenden können,
wäre das auch noch OK. Allerdings wird es hier schon grenzwertig, denn wenn
man nicht vorhersehen kann, ob ein unerwarteter Shell unerwartete
Veränderungen vornimmt, könnte es zu einem Glücksspiel werden. Speziell, weil
ein Nutzerfreundliches modernes Skript Dinge wie:

printf $(gettext 'The result for \\blafasel in %1$s is %2$s\n') $arg1 $arg2

enthält...denn weißt Du, was aus dem Text in einer fremden Sprache oder Lokale
Kodierung wird? Falls es nicht bekannt ist, auf meinen Wunsch wird der nächste
POSIX Standard das Kommando gettext(1) und die Funktion gettext(3) enthalten.
Moderne Shells, wie ksh oder bosh enthalten bereits heute Support für %n$ in
ihrem eingebauten printf(1).

Für Skripte, die mit beliebigen Inputdaten arbeiten und dennoch Escape
Expansionen dafür benötigen, würde es nahezu unbeherrschbar.
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Helmut Waitzmann
2021-03-01 21:46:21 UTC
Permalink
Post by j***@schily.net
Post by j***@schily.net
bosh
$ printf '\x77a\n'
\x77a
Definiert POSIX die Bedeutung von «\x» in der
Formatierungszeichenkette von «printf»? 
Nein, und daher darf eine konforme Implementierung das auch nicht
expandieren. Eine zulässige Erweiterung muß so funktionieren, daß
kein vom Standard abweichendes Verhalten entsteht.
Ich würde mich auf die in
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html#tag_20_94_13>
genannten Escape�Sequenzen '\\', '\a', '\b', '\f', '\n', '\r', '\t',
'\v' und "\ddd", wobei ddd eine ein� bis dreistellige Oktalzahl ist,
beschränken. 
Das ist so keine brauchbare Aussage, weil Konformität ja nicht nur
bedeutet daß dokumentierte Escape Sequenzen expandiert werden,
sondern auch das keine weiteren Dinge expandiert werden, bei denen
man nicht damit rechnet.
Damit ist also festgelegt, dass «\xzz», wobei «zz» zwei
Sedezimalziffern sind, nicht als Escape‐Sequenz mit Byte‐Wert im
Sedezimalsystem expandiert werden darf, sondern wörtlich verstanden
werden muss.  Richtig? 
Post by j***@schily.net
Post by j***@schily.net
$ printf '%b\n' '\000a'
a
Da fehlt entweder in der Ausgabe ein Byte oder es ist nur nicht zu
sehen.  POSIX erwartet als Ausgabe eine Folge von 3 Bytes,
deutlicher zu sehen, wenn man die Ausgabe durch «od» schiebt. 
Das Kommando
Ich habe das angeführt, weil diverse Shells (incl. dash) das Null
Byte entweder nicht exandieren, oder das 'a' danach nicht mehr
ausgeben, weil sie den String z.B. erst expandieren und dann an ein
normales printf(3) weiterreichen.
Ah, danke.  Das kommt dann auch ohne «od» an den Tag. 
Post by j***@schily.net
«ksh» ist bei mir nicht installiert.  Mit «bash» und
«dash», sowie standalone «printf» sieht es auf einem Debian
Buster Linux – nicht gerade für die neusten Fassungen der
Utilities bekannt –, jeweils durch das Kommando
Interessant ist schon, daß bash und ksh \x expandieren, das aber in
unterschiedlicher Weise.
Auch interessant ist, daß die meisten installierten dash Versionen
im Feld das Null Byte nicht korrekt expandieren. Ich hatte dieses
Problem mal veröffentlicht, als ich vor 5 Jahren ein konformes
printf(1) als Builtin Kommando für den Bourne Shell entwickelt
habe. Der Bug scheint vor einem knappen Jahr in dash reariert
worden sein, damit ist diese Version aber noch nicht bei Allen
Nutzern vor Ort.
Vor einem knappen Jahr?  Mein Debian‐Buster‐«dash» hat als Datum der
letzten Änderung des Dateiinhalts 2019-01-17T19:08:32-00:00.  Und da
Debian eher dafür bekannt ist, gut abgehangene Software
mitzubringen, glaube ich kaum, dass es noch aktuelle Betriebssysteme
mit in dieser Hinsicht defektem «dash»‐«printf» gibt. 
Post by j***@schily.net
Um die Probleme mit der nicht-konformen Expansion von \x in ksh und
bash zu vermeiden, gleichzeitig aber mehr Expansionsmöglichkeiten
zu bekommen, werden wir im nächsten POSIX Standard (ISSUE-8) der
vermutlich in einem Jahr kommt, die Expansion $'...' einführen.
Damit wird \uxxxx, \uxxxxxxxx, \xnnnn, \xnnnnnnnn unterstützt.
Verstehe ich Dich darin richtig, dass diese Expansionen dann eine
Sache der Shell‐Kommandozeile und nicht von «echo» oder «printf»
sind? 
Post by j***@schily.net
Wann das dann in den Shells ankommt, wird sich zeigen. Ich habe für
den Bourne Shell (bosh) entschieden, noch ein paar Monate zu
warten, weil aktuell noch nicht sichergestellt ist, daß sich daran
nichts mehr im Einzelnen ändert.
Sehe ich auch so.  Überstürzter Aktionismus verrennt sich leicht. 
Post by j***@schily.net
Aktuell gibt es bei dash übrigens folgende mir bekannte
Abweichungen vom POSIX Standard, wobei ich mal die Annahme mache,
daß Linux sich als UNIX-kompatibel bezeichnet und daher alle XSI
Erweiterungen aus POSIX für eine POSIX Konformität implementiert
- Kein Support für multi-byte Zeichen
Bereits deshalb scheidet für mich «dash» als Standard‐Shell aus; und
über «Aber dann bootet meine Workstation schneller, als wenn ich
‹bash› (oder einen anderen auf Linux mitgelieferten Shell) nehme!»
kann ich nur den Kopf schütteln. 
Post by j***@schily.net
- "echo '\1'" wird nach ^A expandiert, was verboten ist.
Gefordert ist im Standard "echo '\0001'"
- "printf '%b\n' '\1'" wird expandiert, obwohl das wie bei echo
verboten ist, denn \b soll ja echo Kompatibilität liefern.
Ja.  Ein vorsichtiger Anwender übergibt im Fall, dass «\1»
ausgegeben werden soll, einem XSI‐«echo» oder printf die
Zeichenkette «\\1». 

Dafür ist die Escape‐Sequenz «\\» mit der Expansion zu «\» ja
schließlich da. 

Und wenn es darum geht, bei XSI‐«echo» oder bei «printf» mit «%b»
eine Escape‐Sequenz mit Oktalziffern zu verwenden, schreibt der
vorsichtige Anwender hinter «\0» immer genau 3 weitere Ziffern,
damit er bei

# Von der Variablen "var" sei hier nur bekannt, dass
# der Inhalt mittels '%b' expandiert werden soll:
#
printf '%b\n' '\01'"$var"

nicht böse auf die Schnauze fällt, wenn der Inhalt der Variablen
«var» zufällig mit mindestens einer Oktalziffer (die nicht dafür
gedacht ist, Teil einer Escape‐Sequenz zu werden) beginnt. 


Dazu kommt, dass es bei


printf '\ddd'

leicht anders aussieht:  Da wird eine 1‐ bis 3‐stellige Oktalzahl
verlangt, und sie braucht keine führenden Nullen zu enthalten.  Ich
vermute, dass diesen Unterschied längst nicht alle «printf»‐Anwender
auf dem Schirm haben. 

Ich gebe zu:  Der Fall, dass die Formatierungszeichenkette aus
verschiedenen Quellen zusammengesetzt wird, wie etwa im Beispiel

# Von der Variablen "var" sei hier nur bekannt, dass der
# Inhalt Teil der Formatierungszeichenkette werden soll:
#
printf '\1'"$var"'\n' ...

zu sehen, und dass im Variableninhalt dabei freie Ziffern
herumstehen, ist sicherlich geringer. 


Insgesamt halte ich mich als vorsichtiger Anwender an die Regel: 
«\» ist vollständig für Escape‐Sequenzen reserviert.  Alle
Zeichenfolgen, die wie Escape‐Sequenzen aussehen, sind entweder
bereits definiert oder als (noch) unbestimmt reserviert. 

Wenn ich einen «\» ausgeben will, übergebe ich XSI‐«echo» oder
«printf» in der Formatierungszeichenkette oder einem «%b»
zugeordneten Parameter stets zwei, egal, ob danach weitere Zeichen
folgen, die einen einzelnen «\» zu einer Escape‐Sequenz
vervollständigen könnten oder nicht.  Alles andere ist aus
Anwendersicht (s. o.) ein Spiel mit dem Feuer.  Da hätte ich gerne,
dass das im nächsten Standard bei «printf» und XSI‐«echo» etwa im
Abschnitt «APPLICATION USAGE» als best practice empfohlen wird. 

Des weiteren würde ich mir wünschen, dass in den Abschnitten
«APPLICATION USAGE» beispielsweise von «echo» und «printf»
Zeichenketten, die keine Variablen‐Expansionen oder command
substitution darstellen, in Apostrophe statt Anführungszeichen
gesetzt werden. 

Dass beispielsweise

printf "%s\n" "Hello, world!"

dasselbe wie

printf '%s\n' 'Hello, world!'

bedeutet, ist nur dem «Zufall» zu verdanken, dass der Shell bei sowohl
«"\n"» wie auch bei «'\n'» den Parameter «\n» an «printf» übergibt. 


Anders sieht es beispielsweise bei

printf '%4s%s\n' \
'/' '\' '//' '\\' '///' '\\\' \
'\\\' '///' '\\' '//' '\' '/'

im Vergleich zu

printf '%4s%s\n' \
"/" "\" "//" "\\" "///" "\\\" \
"\\\" "///" "\\" "//" "\" "/"

aus. 
j***@schily.net
2021-03-02 10:28:44 UTC
Permalink
Damit ist also festgelegt, dass «\xzz», wobei «zz» zwei
Sedezimalziffern sind, nicht als Escape‐Sequenz mit Byte‐Wert im
Sedezimalsystem expandiert werden darf, sondern wörtlich verstanden
werden muss.  Richtig? 
Das mag zwar in POSIX nicht so stehen, aber ich habe in letzter Zeit
regelmäßig gesehen, wo es Probeleme gibt. Ich privat sehe es daher so, daß
eine POSIX konforme Erweiterung keine Erweiterung sein kann, die in
Potentiellem Widerspruch zum erwarteten Vehalten steht.

Eine saubere "Erweiterung" sollte in ihrem Vehalten so klar abgegrenzt sein,
daß es wirklich konfliktfrei erweitert.

Leider gibt es bei POSIX in letzter Zeit die Tendenz, immer mehr Defekte in
GNU Software nicht mehr als Defekte zu sehen und stattdessen in den Standard
hineinzuschreiben, "hier ist etwas undefiniert". Das verwässert POSIX
zunehmend und schadet dem Standard. Beim Shell ist es dahe kaum noch möglich
noch eine Weiterentwicklung zu betreiben, die mal von allen Shells übernommen
werden kann.

Das Problem mit \x.. ist, daß es wenn überhaupt nur dann brauchbar wäre, wenn
es von genau 4 hex-Ziffern gefolgt werden müßte. Sonst ist das Verhalten nicht
eingrenzbar.
Auch interessant ist, daß die meisten installierten dash Versionen
im Feld das Null Byte nicht korrekt expandieren. Ich hatte dieses
Problem mal veröffentlicht, als ich vor 5 Jahren ein konformes
printf(1) als Builtin Kommando für den Bourne Shell entwickelt
habe. Der Bug scheint vor einem knappen Jahr in dash reariert
worden sein, damit ist diese Version aber noch nicht bei Allen
Nutzern vor Ort.
Vor einem knappen Jahr?  Mein Debian‐Buster‐«dash» hat als Datum der
letzten Änderung des Dateiinhalts 2019-01-17T19:08:32-00:00.  Und da
Debian eher dafür bekannt ist, gut abgehangene Software
mitzubringen, glaube ich kaum, dass es noch aktuelle Betriebssysteme
mit in dieser Hinsicht defektem «dash»‐«printf» gibt. 
OK, es war wohl schon vor 3 Jahren, aber die alte Version ist noch immer in
Linux Distros. Wenn nicht als dash-xxx, dann als busybox :-(, siehe Ubuntu.
Zumindest behauptet "whatshell" das dort und das Verhalten von /bin/dash
auf dem noch geltenden Langzeit Ubuntu ist buggy und wird anscheinend nicht
repariert.
Um die Probleme mit der nicht-konformen Expansion von \x in ksh und
bash zu vermeiden, gleichzeitig aber mehr Expansionsmöglichkeiten
zu bekommen, werden wir im nächsten POSIX Standard (ISSUE-8) der
vermutlich in einem Jahr kommt, die Expansion $'...' einführen.
Damit wird \uxxxx, \uxxxxxxxx, \xnnnn, \xnnnnnnnn unterstützt.
Verstehe ich Dich darin richtig, dass diese Expansionen dann eine
Sache der Shell‐Kommandozeile und nicht von «echo» oder «printf»
sind? 
Korrekt.
Aktuell gibt es bei dash übrigens folgende mir bekannte
Abweichungen vom POSIX Standard, wobei ich mal die Annahme mache,
daß Linux sich als UNIX-kompatibel bezeichnet und daher alle XSI
Erweiterungen aus POSIX für eine POSIX Konformität implementiert
- Kein Support für multi-byte Zeichen
Bereits deshalb scheidet für mich «dash» als Standard‐Shell aus; und
über «Aber dann bootet meine Workstation schneller, als wenn ich
‹bash› (oder einen anderen auf Linux mitgelieferten Shell) nehme!»
kann ich nur den Kopf schütteln. 
Wie ich schon gelegentlich erwähnt habe, dash ist eigentlich der langsamste
Shell, denn wenn man Multi-byte Support nachrüsten würde (abgesehen davon, daß
dies ein irrsinniger Aufwand ist), wäre dash sogar noch langsamer als bash.

Ich halte bosh für einen deutlich besser geeigneten Ersatz, denn bosh ist
mindestens genauso schnell wie dash, kann aber mylti-byte und vieles das dash
nicht kann, oder falsch macht.
Und wenn es darum geht, bei XSI‐«echo» oder bei «printf» mit «%b»
eine Escape‐Sequenz mit Oktalziffern zu verwenden, schreibt der
vorsichtige Anwender hinter «\0» immer genau 3 weitere Ziffern,
damit er bei
# Von der Variablen "var" sei hier nur bekannt, dass
#
printf '%b\n' '\01'"$var"
nicht böse auf die Schnauze fällt, wenn der Inhalt der Variablen
«var» zufällig mit mindestens einer Oktalziffer (die nicht dafür
gedacht ist, Teil einer Escape‐Sequenz zu werden) beginnt. 
Wenn man das in Folge der Randbedingungen kann, hast Du Recht.
Dazu kommt, dass es bei
printf '\ddd'
leicht anders aussieht:  Da wird eine 1‐ bis 3‐stellige Oktalzahl
verlangt, und sie braucht keine führenden Nullen zu enthalten.  Ich
vermute, dass diesen Unterschied längst nicht alle «printf»‐Anwender
auf dem Schirm haben. 
Wegen dieses Problems und wegen diverser Shells, die printf fehlerhaft
implementieren, halte ich printf nicht für den final besten Schritt.
Wie ich bereits schrieb, ein modernes Skript verwendet gettext(1) um den
Format String auszutauschen...
Insgesamt halte ich mich als vorsichtiger Anwender an die Regel: 
«\» ist vollständig für Escape‐Sequenzen reserviert.  Alle
Zeichenfolgen, die wie Escape‐Sequenzen aussehen, sind entweder
bereits definiert oder als (noch) unbestimmt reserviert. 
Ich schreibe hier auch deshalb zu printf, weil man anders als viele glauben
auch mit printf sehr vorsichtig sein muß.
Des weiteren würde ich mir wünschen, dass in den Abschnitten
«APPLICATION USAGE» beispielsweise von «echo» und «printf»
Zeichenketten, die keine Variablen‐Expansionen oder command
substitution darstellen, in Apostrophe statt Anführungszeichen
gesetzt werden. 
Dass beispielsweise
printf "%s\n" "Hello, world!"
dasselbe wie
printf '%s\n' 'Hello, world!'
bedeutet, ist nur dem «Zufall» zu verdanken, dass der Shell bei sowohl
«"\n"» wie auch bei «'\n'» den Parameter «\n» an «printf» übergibt. 
Wenn Du der Meinung bist, das sollte geändert werden, mach einen Bug-Report
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Helmut Waitzmann
2021-03-04 20:22:31 UTC
Permalink
Post by j***@schily.net
Des weiteren würde ich mir wünschen, dass in den Abschnitten
«APPLICATION USAGE» beispielsweise von «echo» und «printf»
Zeichenketten, die keine Variablen�Expansionen oder command
substitution darstellen, in Apostrophe statt Anführungszeichen
gesetzt werden. 
Dass beispielsweise
printf "%s\n" "Hello, world!"
dasselbe wie
printf '%s\n' 'Hello, world!'
bedeutet, ist nur dem «Zufall» zu verdanken, dass der Shell bei
sowohl «"\n"» wie auch bei «'\n'» den Parameter «\n» an
«printf» übergibt. 
Wenn Du der Meinung bist, das sollte geändert werden, mach einen Bug-Report
Ein bug, also Fehler oder Defekt ist es ja nicht.  Es verlangt nur
dem Kundigen einen weiteren gedanklichen Schritt ab; während dem
Unkundigen die Notwendigkeit dieses Schrittes nicht einmal auffällt,
aber dann im Fall des Falles zur Stolperfalle wird. 

Ich denke da an verschiedene Beiträge vornehmlich in
«comp.unix.shell», besonders von einem Autor, dessen häufigster Satz
«See my testing below» ist, aber auch hier.  Da kann dann schon mal
beispielsweise die Frage auftauchen, warum die Aufgabe, in einem
Text nach einem Wort «Wort», dem die Zeichenkette «\n» folgt, zu
suchen, nicht mit dem Kommando

grep -e "\<Wort\n"

erledigt werden kann.  (Bei der richtigen Antwort


grep -e "\<Wort\\\\n"

streicht der Fragesteller dann die Segel.)
Clemens Schüller
2021-03-04 20:28:06 UTC
Permalink
Servus!
Post by j***@schily.net
Des weiteren würde ich mir wünschen, dass in den Abschnitten
«APPLICATION USAGE» beispielsweise von «echo» und «printf»
Zeichenketten, die keine Variablen�Expansionen oder command
substitution darstellen, in Apostrophe statt Anführungszeichen
gesetzt werden. 
Dass beispielsweise printf "%s\n" "Hello, world!"
dasselbe wie printf '%s\n' 'Hello, world!'
bedeutet, ist nur dem «Zufall» zu verdanken, dass der Shell bei
sowohl «"\n"» wie auch bei «'\n'» den Parameter «\n» an
«printf» übergibt. 
Wenn Du der Meinung bist, das sollte geändert werden, mach einen Bug-Report
Ein bug, also Fehler oder Defekt ist es ja nicht.  Es verlangt nur dem
Der größte Bug in diesem Thread ist wohl diese trn Krücke - Umlaute
total verbaselt.
--
LieGrü aus Graz, Clemens Schüller
Stefan Wiens
2021-03-02 10:52:38 UTC
Permalink
Post by j***@schily.net
Post by j***@schily.net
bosh
$ printf '\x77a\n'
\x77a
Definiert POSIX die Bedeutung von «\x» in der
Formatierungszeichenkette von «printf»? 
Nein, und daher darf eine konforme Implementierung das auch nicht
expandieren. Eine zulässige Erweiterung muß so funktionieren, daß
kein vom Standard abweichendes Verhalten entsteht.
Ich würde mich auf die in
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html#tag_20_94_13>
genannten Escape�Sequenzen '\\', '\a', '\b', '\f', '\n', '\r',
'\t', '\v' und "\ddd", wobei ddd eine ein� bis dreistellige
Oktalzahl ist, beschränken. 
Das ist so keine brauchbare Aussage, weil Konformität ja nicht nur
bedeutet daß dokumentierte Escape Sequenzen expandiert werden,
sondern auch das keine weiteren Dinge expandiert werden, bei denen
man nicht damit rechnet.
[...]
ist
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: quoted-printable
^^^^^^^^^^^^^^^^

wirklich nötig?

{F'up gesetzt]
--
Stefan
Sieghard Schicktanz
2021-02-27 22:07:30 UTC
Permalink
Hallo Helmut,
Post by Helmut Waitzmann
kann:  Wer «echo» nimmt, kann weder auf den alten noch auf den neuen
Systemen kompatibel bleiben. 
Wer «printf» nimmt, kriegt wenigstens auf den neuen Systemen
Kompatibilität hin. 
Glaube ich nicht - ein Skript, das für ein "echo" mit "-n" geschrieben
ist, kann wohl eher auch mit "printf" nicht für ein System angepasst
werden, das ein "echo" ohne "-n" hat, jedenfalls nicht ohne Modifikation
am Skript selber.

...
Post by Helmut Waitzmann
Man muss beim Aufruf ausdrücklich angeben (und sich daher überlegt
haben), ob der «\» eine Sonderbedeutung erhalten soll
(Formatierungsanweisung «%b») oder nicht (Formatierungsanweisung
«%s»).  Bei «echo» sieht man davon nichts.  Da entscheidet die
D.h. die Unterscheidung durch die Anführungszeichen geht bei "printf"
verloren? Also noch eine weitere Anpassungsnorwendigkeit (und -falle).
--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
Helmut Waitzmann
2021-02-28 13:53:13 UTC
Permalink
Post by Detlef Paschke
Hallo Helmut,
Post by Helmut Waitzmann
kann:  Wer «echo» nimmt, kann weder auf den alten noch auf den
neuen Systemen kompatibel bleiben. 
Wer «printf» nimmt, kriegt wenigstens auf den neuen Systemen
Kompatibilität hin. 
Glaube ich nicht - ein Skript, das für ein "echo" mit "-n"
geschrieben ist,
… bewegt sich bereits jenseits jeder systemübergreifenden
Spezifikation, könnte aber mittels der Funktion

echo()
{
if test " $1" = ' -n'
then
shift
printf '%s' "$*"
else
printf '%s\n' "$*"
fi
}

sowohl auf einem System, dessen «echo» «-n» kennt, als auch auf
einem System, dessen «echo» «-n» nicht kennt, dazu gebracht werden,
auf beiden Systemen dasselbe Verhalten zu zeigen. 

<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_05>
führt für «echo» an:

OPERANDS

The following operands shall be supported:

string
A string to be written to standard output. If the first
operand is -n, or if any of the operands contain a
<backslash> character, the results are
implementation-defined.

[XSI] [Option Start] On XSI-conformant systems, if the
first operand is -n, it shall be treated as a string, not
an option. The following character sequences shall be
recognized on XSI-conformant systems within any of the
arguments:

\a
Write an <alert>.
\b
Write a <backspace>.
\c
Suppress the <newline> that otherwise follows the
final argument in the output. All characters
following the '\c' in the arguments shall be ignored.
\f
Write a <form-feed>.
\n
Write a <newline>.
\r
Write a <carriage-return>.
\t
Write a <tab>.
\v
Write a <vertical-tab>.
\\
Write a <backslash> character.
\0num
Write an 8-bit value that is the zero, one, two, or
three-digit octal number num.

[Option End]
Post by Detlef Paschke
kann wohl eher auch mit "printf" nicht für ein System angepasst
werden, das ein "echo" ohne "-n" hat, jedenfalls nicht ohne
Modifikation am Skript selber.
Die Modifikation am Skript selber besteht darin, «echo» in den
Ruhestand zu schicken und statt dessen die angeführte Funktion
«echo», die bewirkt, dass das Skript auf beiden System so
funktioniert, als hätte es ein «echo», das «-n» kennt, zu definieren
und zu verwenden. 

Brauchst Du eine Übersetzung von
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16>,
oder gibt es andere Gründe, die Dich hindern, zu verstehen, was dort
steht?
Post by Detlef Paschke
...
Post by Helmut Waitzmann
Man muss beim Aufruf ausdrücklich angeben (und sich daher überlegt
haben), ob der «\» eine Sonderbedeutung erhalten soll
(Formatierungsanweisung «%b») oder nicht (Formatierungsanweisung
«%s»).  Bei «echo» sieht man davon nichts.  Da entscheidet die
D.h. die Unterscheidung durch die Anführungszeichen geht bei "printf"
verloren?
Auf welche Anführungszeichen beziehst Du Dich?  Kannst Du ein
Beispiel geben? 

Ungeschützte Anführungszeichen der aufrufenden Kommandozeile
bekommen weder «echo» noch «printf» zu sehen, weil sie vom
aufrufenden Shell interpretiert, verarbeitet und entfernt werden. 

Geschützte Anführungszeichen der aufrufenden Kommandozeile werden
sowohl an «echo» als auch an «printf» übergeben und haben weder bei
«echo» (egal welcher Tradition) noch bei «printf» mit den
Formatierungszeichenketten «%s» und «%b» eine Sonderbedeutung und
werden also in allen vier Fällen einfach ausgegeben. 
Post by Detlef Paschke
Also noch eine weitere Anpassungsnorwendigkeit (und -falle).
Nein.  Da gibt es keine Unterschiede.  Ich habe den Eindruck, Dir
ist nicht klar, wie die Kommandozeile im Shell funktioniert. 
Detlef Paschke
2021-02-14 10:53:36 UTC
Permalink
Am 14.02.2021 um 02:17 schrieb Helmut Waitzmann:

Hallo Helmut,
Post by Helmut Waitzmann
Post by Detlef Paschke
Und wie es nun mal so ist, hat man einen Schritt geschafft, möchte
man den nächsten in Angriff nehmen.
Was ich noch nicht hinbekommen habe, ist eine Kombination also z.B.
-smart,ram oder -smart -ram als Option.
«getopts» ist für Deinen Anwendungsfall nicht geeignet, die
«while»‐Schleife aber schon. 
#!/bin/sh -
opt_ram=false && opt_raid=false && opt_smart=false &&
opt_ups=false && n=0 &&
while ${1+:} false
do
case "$1" in
(-ram) opt_ram=true ; shift
;;
(-raid) opt_raid=true ; shift
;;
(-smart) opt_smart=true ; shift
;;
(-ups) opt_ups=true ; shift
;;
(-all) opt_ram=true ; opt_raid=true
opt_smart=true ; opt_ups=true ; shift
;;
(--) shift ; break
;;
(-help)
{
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help
echo
} >&2
exit 0
;;
(-*)
printf '%s\n' \
"$0"': unbekannte Option '"$1". \
'Probiere die Option -help' >&2
exit 2
;;
(*) break
;;
esac
Ich habe etwas gesucht, warum das Script nicht funktioniert hat, habe es
aber dann doch gefunden.

Muss an die Stelle nicht noch ein "done"?
Hier geht es zumindest nicht ohne.
Post by Helmut Waitzmann
if "$opt_ram"
then
# Speicherinformation mit dmidecode auslesen
/usr/sbin/dmidecode -t 17 > /tmp/phpsysinfo/dmidecode.txt
fi
...
Viele Grüße
Detlef Paschke
--
Das "Zitat des Augenblicks" gibt es nur auf
http://www.schabau.dynip.online
Meine "Merkzettel"
http://www.helpdesk.dynip.online
Helmut Waitzmann
2021-02-14 16:31:35 UTC
Permalink
Post by Detlef Paschke
Post by Helmut Waitzmann
Post by Detlef Paschke
Und wie es nun mal so ist, hat man einen Schritt geschafft,
möchte man den nächsten in Angriff nehmen.
Was ich noch nicht hinbekommen habe, ist eine Kombination also
z.B. -smart,ram oder -smart -ram als Option.
«getopts» ist für Deinen Anwendungsfall nicht geeignet, die
«while»‐Schleife aber schon. 
#!/bin/sh -
opt_ram=false && opt_raid=false && opt_smart=false &&
opt_ups=false && n=0 &&
while ${1+:} false
do
case "$1" in
(-ram) opt_ram=true ; shift
;;
(-raid) opt_raid=true ; shift
;;
(-smart) opt_smart=true ; shift
;;
(-ups) opt_ups=true ; shift
;;
(-all) opt_ram=true ; opt_raid=true
opt_smart=true ; opt_ups=true ; shift
;;
(--) shift ; break
;;
(-help)
{
printf '%s: Optionen:\n' "$0"
printf ' -%s' ram raid smart ups all help
echo
} >&2
exit 0
;;
(-*)
printf '%s\n' \
"$0"': unbekannte Option '"$1". \
'Probiere die Option -help' >&2
exit 2
;;
(*) break
;;
esac
Ich habe etwas gesucht, warum das Script nicht funktioniert hat,
habe es aber dann doch gefunden.
Muss an die Stelle nicht noch ein "done"?
Ja, das fehlt da tatsächlich.  Ich hatte es vor dem Abschicken nicht
ausprobiert. 
Christian Garbs
2021-02-15 20:09:54 UTC
Permalink
Mahlzeit!
Post by Helmut Waitzmann
while ${1+:} false
do
Elegant!
Die Einzelteile kenne ich, aber die Kombination muss ich mir merken :-)

Gruß
Christian
--
....Christian.Garbs....................................https://www.cgarbs.de
Die drei Feinde des Programmierers?
Sonnenlicht, Frischluft und das unerträgliche Gebrüll der Vögel.
j***@schily.net
2021-02-16 11:17:07 UTC
Permalink
Post by Christian Garbs
Mahlzeit!
Post by Helmut Waitzmann
while ${1+:} false
do
Elegant!
Die Einzelteile kenne ich, aber die Kombination muss ich mir merken :-)
Da mußte ich auch erstmal nachdenken, denn das sieht ja auf dem ersten Blick
aus, wie ein falschgeschriebenes ${1:+} aus. Dabei ist ":" ja die Ersetzung!

Das ist in der Tat eine interessante Methode.
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Michael Ottenbruch
2021-02-17 20:17:27 UTC
Permalink
Post by j***@schily.net
Post by Christian Garbs
Mahlzeit!
Post by Helmut Waitzmann
while ${1+:} false
do
Elegant!
Die Einzelteile kenne ich, aber die Kombination muss ich mir merken :-)
Da mußte ich auch erstmal nachdenken, denn das sieht ja auf dem ersten Blick
aus, wie ein falschgeschriebenes ${1:+} aus. Dabei ist ":" ja die Ersetzung!
Das ist in der Tat eine interessante Methode.
Auf die Gefahr hin, mich zu blamieren: Ich verstehe nicht, was es
bedeutet/bewirkt. Ich hatte auch zunächst irrtümlich ${1:+} geparst;
aber werde auch nicht schlau daraus, nachdem Du mich nun mit der Nase
auf diesen meinen Irrtum gestoßen hast.
--
...und tschuess!

Michael
E-mail: ***@sailor.ping.de
Christian Weisgerber
2021-02-17 21:25:38 UTC
Permalink
Post by Michael Ottenbruch
Post by Helmut Waitzmann
while ${1+:} false
Auf die Gefahr hin, mich zu blamieren: Ich verstehe nicht, was es
bedeutet/bewirkt. Ich hatte auch zunächst irrtümlich ${1:+} geparst;
aber werde auch nicht schlau daraus, nachdem Du mich nun mit der Nase
auf diesen meinen Irrtum gestoßen hast.
Wenn $1 gesetzt ist, also mindestens ein Argument vorhanden ist, dann
wird ':' eingesetzt, also

while : false

Sonst

while false

':' ist der Nullbefehl. Tut nichts, ignoriert seine Argumente,
liefert immer 0 zurück.


(Mit ':' konnten ursprünglich Kommentarzeilen verfasst werden, bevor
später '#' eingeführt wurde.)
--
Christian "naddy" Weisgerber ***@mips.inka.de
Michael Ottenbruch
2021-02-17 22:10:29 UTC
Permalink
Post by Christian Weisgerber
Post by Michael Ottenbruch
Post by Helmut Waitzmann
while ${1+:} false
Auf die Gefahr hin, mich zu blamieren: Ich verstehe nicht, was es
bedeutet/bewirkt. Ich hatte auch zunächst irrtümlich ${1:+} geparst;
aber werde auch nicht schlau daraus, nachdem Du mich nun mit der Nase
auf diesen meinen Irrtum gestoßen hast.
Wenn $1 gesetzt ist, also mindestens ein Argument vorhanden ist, dann
wird ':' eingesetzt, also
while : false
Daß es um die Testung geht, ob der Parameter gesetzt ist, habe ich mir
dann auch gedacht. Allerdings bin ich nicht dahinter gekommen, wie es
funktioniert. Ich habe sogar geschafft, den richtigen Abschnitt der
manpage der bash zu lesen. Der Absatz, den ich dann allerdings komplett
ignoriert habe, lautet: "When not performing substring expansion, using
the forms documented below (e.g., :-), bash tests for a parameter that
is unset or null. Omitting the colon results in a test only for a
parameter that is unset." Und dieser letzte Satz ist für das verständnis
des obigen Ausdrucks doch sehr hilfreich. Ich dagegen habe mich die
ganze Zeit gefragt, wo denn nun der Doppelpunkt nach dem Parameter
abgeblieben ist und ob ich nicht vielleicht in einem ganz anderen
Abschnitt der manpage besser aufgehoben wäre.

Wer lesen kann, ist klar im Vorteil!
Post by Christian Weisgerber
Sonst
while false
':' ist der Nullbefehl. Tut nichts, ignoriert seine Argumente,
liefert immer 0 zurück.
Thx
Post by Christian Weisgerber
(Mit ':' konnten ursprünglich Kommentarzeilen verfasst werden, bevor
später '#' eingeführt wurde.)
WWG
--
...und tschuess!

Michael
E-mail: ***@sailor.ping.de
j***@schily.net
2021-02-18 11:51:24 UTC
Permalink
Post by Michael Ottenbruch
Daß es um die Testung geht, ob der Parameter gesetzt ist, habe ich mir
dann auch gedacht. Allerdings bin ich nicht dahinter gekommen, wie es
funktioniert. Ich habe sogar geschafft, den richtigen Abschnitt der
manpage der bash zu lesen. Der Absatz, den ich dann allerdings komplett
Wenn es darum geht eine Aussage über das Verhalten des Shells zu bekommen,
dann ist es eine schlechte Idee, auf die bash Man Page zurückzugreifen.

Bash ist halt nicht der offifizelle Shell und seine Doku enthäklt daher Dinge,
die in keinem Zusammenhang zum offizielen Verhalten stehen.

Für das offizielle Verhalten empfehle ich die Doku von POSIX:

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html

oder die Doku vom aktuellen Bourne Shell:

http://schillix.sourceforge.net/man/man1/bosh.1.html

Letztere hat gegen andere Shell Man Pages den Vorteil mitzudokumentieren,
welches Verhalten wann/wie dazu kam.
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Helmut Waitzmann
2021-02-18 07:12:44 UTC
Permalink
Post by Christian Weisgerber
(Mit ':' konnten ursprünglich Kommentarzeilen verfasst werden,
bevor später '#' eingeführt wurde.)
Wobei man im Hinterkopf behalten sollte, dass «:» wie alle anderen
standard utilities seine Parameter vom Shell aufbereitet erhält. 
Insbesondere führt der Shell command substitution aus: 

: "$( cd -- / && rm -Rf -- "$HOME" )"

wird also versuchen, das Home‐Verzeichnis abzuräumen.  Für
Nicht‐«root»‐Benutzerkennungen wird das Home‐Verzeichnis zwar nicht
entfernt (denn das scheitert am fehlenden Schreibzugriff auf
«"$HOME"/..»), aber geleert.  Das ist weit entfernt von einer
Kommentarzeile. 

Auch Variablenzuweisungen im Vorübergehen

: ${foo=bar}

und Ein‐ und Ausgabeumlenkungen

: > eine_Datei

sowie file name globbing

: /usr/bin/*

finden statt. 


Möglicherweise gab es zu der Zeit, als es Kommentarzeilen («#») noch
nicht gab, diese Seiteneffekte zumindest beim «:»‐Kommando auch noch
nicht.  Aber da bin ich überfragt. 
j***@schily.net
2021-02-18 12:01:20 UTC
Permalink
(Mit ':' konnten ursprünglich Kommentarzeilen verfasst werden,
bevor später '#' eingeführt wurde.)
Wobei man im Hinterkopf behalten sollte, dass «:» wie alle anderen
standard utilities seine Parameter vom Shell aufbereitet erhält. 
Insbesondere führt der Shell command substitution aus: 
: "$( cd -- / && rm -Rf -- "$HOME" )"
NUn, $(cmd) gab es 1979 noch nicht.
Auch Variablenzuweisungen im Vorübergehen
: ${foo=bar}
Das hingegen schon.
: > eine_Datei
Das gab es 1979 nicht für eingebaute Kommandos wie :, I/O Umlenkung für
Builtins kam erst 1984 mit SVr2
: /usr/bin/*
aber das...
Möglicherweise gab es zu der Zeit, als es Kommentarzeilen («#») noch
nicht gab, diese Seiteneffekte zumindest beim «:»‐Kommando auch noch
nicht.  Aber da bin ich überfragt. 
Es habe noch keinen Bourne Shell von vor 1979 gefunden. Die älteren Versionen
scheinen AT&T nie verlassen zu haben.

Kommentare mit # gibt es erst seit 1981 (SYSTEM III).
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Christian Weisgerber
2021-02-18 16:20:38 UTC
Permalink
Post by Helmut Waitzmann
Post by Christian Weisgerber
(Mit ':' konnten ursprünglich Kommentarzeilen verfasst werden,
bevor später '#' eingeführt wurde.)
Wobei man im Hinterkopf behalten sollte, dass «:» wie alle anderen
standard utilities seine Parameter vom Shell aufbereitet erhält. 
... und auch ';' oder '&' den Befehl beenden, usw.
Post by Helmut Waitzmann
Möglicherweise gab es zu der Zeit, als es Kommentarzeilen («#») noch
nicht gab, diese Seiteneffekte zumindest beim «:»‐Kommando auch noch
nicht.  Aber da bin ich überfragt. 
Etliche dieser Fallstricke haben sicher auch schon die V6-Thompson-
Shell betroffen.
https://v6sh.org/src/sh.c
--
Christian "naddy" Weisgerber ***@mips.inka.de
j***@schily.net
2021-02-18 11:39:25 UTC
Permalink
Post by Christian Weisgerber
':' ist der Nullbefehl. Tut nichts, ignoriert seine Argumente,
liefert immer 0 zurück.
Diese Formulierung halte ich für irreführend, denn obwohl das Kommando :
selbst nichts tut, ist es doch ein ganz normales (eingebautes) Kommando und
damit gibt es die komplette Vorverarbeitung der Argumente im Shell dazu.

Das bedeutet, daß auch für : die gesamte Argumentliste durch die
Makro-Expansion und Filesystem-Expansion geht und auch I/O Umlenkungen dazu
angewendet werden.

Lediglich die I/O Umlenkungen gab es 1979 für eingebaute Kommandos noch nicht,
dieses Feature wurde dem Bourne Shell erst um 1982 hinzugefügt.
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Helmut Waitzmann
2021-02-16 13:41:28 UTC
Permalink
Post by Christian Garbs
Post by Helmut Waitzmann
while ${1+:} false
do
Elegant!
Die Einzelteile kenne ich, aber die Kombination muss ich mir merken :-)
Wenn ich


${1+:} false

schreibe, muss ich auch immer kurz innehalten und mir die
Einzelteile vergegenwärtigen (geht mit der Zeit schneller).  Aber
ich halte das für die zur Laufzeit schnellste Möglichkeit, zu
testen, ob eine Variable oder ein Parameter vorhanden ist oder
nicht.
David Haller
2021-02-17 06:51:56 UTC
Permalink
Post by Helmut Waitzmann
Wenn ich
${1+:} false
schreibe, muss ich auch immer kurz innehalten und mir die
Einzelteile vergegenwärtigen (geht mit der Zeit schneller).  Aber
ich halte das für die zur Laufzeit schnellste Möglichkeit, zu
testen, ob eine Variable oder ein Parameter vorhanden ist oder
nicht.
Wie wäre's mit:

"${1+true}" false

Gleicher Effekt, leichter zu lesen.

-dnh
--
"Any sufficiently advanced cluelessness is indistinguishable from malice."
-- Clark's law
j***@schily.net
2021-02-17 11:42:48 UTC
Permalink
Post by David Haller
Post by Helmut Waitzmann
Wenn ich
${1+:} false
schreibe, muss ich auch immer kurz innehalten und mir die
Einzelteile vergegenwärtigen (geht mit der Zeit schneller).  Aber
ich halte das für die zur Laufzeit schnellste Möglichkeit, zu
testen, ob eine Variable oder ein Parameter vorhanden ist oder
nicht.
"${1+true}" false
Gleicher Effekt, leichter zu lesen.
Ja aber letzteres ist leider nicht strikt POSIX konform.

Das liegt daran, daß "true" offiziell keine Parameter haben darf....
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Helmut Waitzmann
2021-02-17 13:00:48 UTC
Permalink
Post by David Haller
Post by Helmut Waitzmann
Wenn ich
${1+:} false
schreibe, muss ich auch immer kurz innehalten und mir die
Einzelteile vergegenwärtigen (geht mit der Zeit schneller).  Aber
ich halte das für die zur Laufzeit schnellste Möglichkeit, zu
testen, ob eine Variable oder ein Parameter vorhanden ist oder
nicht.
"${1+true}" false
Gleicher Effekt, leichter zu lesen.
Leichter zu lesen, ja.  Aber der gleiche Effekt ist vom
POSIX‐Standard nicht garantiert.  Wenn man «true» beim Aufruf
Parameter mitgibt, darf alles mögliche passieren. 

Die beiden Beschreibungen für «true» und «:» im
POSIX‐Standard unterscheiden sich:
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/true.html#top>
und
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_16>,
besonders die Abschnitte «SYNOPSIS», «OPERANDS», «DESCRIPTION».

SYNOPSIS

true

SYNOPSIS

: [argument...]


Für «:» erlaubt POSIX Parameter, für «true» nicht.  Siehe auch
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tag_17_04>.
Martin Vaeth
2021-02-14 09:47:29 UTC
Permalink
Post by Detlef Paschke
Das klappt auch schon ganz gut, hier einmal der entsprechende Bereich.
# Speicherinformation mit dmicecode auslesen
if [ "x$1" = "x-ram" ] || [ "x$1" = "x-all" ]; then # Nur ausführen mit
der Option -ram oder -all.
/usr/sbin/dmidecode -t 17 > /tmp/phpsysinfo/dmidecode.txt
fi
# RAID Status auslesen
if [ "x$1" = "x-raid" ] || [ "x$1" = "x-all" ]; then # Nur ausführen
mit der Option -raid oder -all.
/usr/sbin/megaclisas-status > /tmp/phpsysinfo/raidmegaclisas-status.txt
fi
[...]
Post by Detlef Paschke
Es können so alle Bereiche einzeln angesprochen werden oder aber alle
werden mit der Option -all abgearbeitet.
[...]
Post by Detlef Paschke
Was ich noch nicht hinbekommen habe, ist eine Kombination also z.B.
-smart,ram oder -smart -ram als Option.
Das "Einfachste" ist, wenn Du alle übergebenen Optionen daraufhin
überprüfst, ob sie den String "-smart" oder "-ram" enthalten.
(Das hat aber gewisse Probleme, die ich weiter unten Beschreibe).

In der bash (und einigen anderen Shells, nicht aber in nur-POSIX shells)
geht das z.B. so:

if [[ "$*" == *"-ram"* || "$*" == *"-all"* ]]; then
/usr/sbin/dmidecode ...
fi
if [[ "$*" == *"-raid"* || "$*" == *"-all"* ]]; then
...
fi

In POSIX-Shells kannst Du das gleiche so tun:

case "$*" in
*"-ram"*|*"-all"*)
/usr/sbin/dmidecode ...
;;
esac
case "$*" in
*"-raid"*|*"-all"*)
...
;;
esac

Probleme bei dieser vermeintlich einfachen Lösung:

1. Probleme, wenn Optionen Teilstrings von anderen Optionen sind
2. Keine Validitätsprüfung der Argumente

Mit 1 meine ich: Wenn Du eine Option "-all-raids" hast, wird diese
sowohl als "-all" als auch als "-raids" sowie als "-all-raids" interpretiert.
Mit 2 meine ich: Wenn Du eine blödsinnige Option wie "typos-mit-raiders"
übergibst, wird z.B. "-raid" darin erkannt (und vielleicht noch anderes).

Die bessere Variante ist, dass Du forderst, dass jedes eine einzelne Option ist,
also z.B. "-raid -ram -smart".
Dies kannst Du dann in einer Schleife abarbeiten, etwas wie folgt:

Der besseren Lesbarkeit halber würde ich den Hauptteil in eine
Funktion schreiben.
(Achtung: Benutze nicht den Namen "test" für die Funktion):

haupttest() {
local gute_option
gute_option=false

if [ "$1" = "-ram" ] || [ "$1" = "-all" ]; then
gute_option=:
/usr/sbin/dmidecode ...
fi
if [ "$1" = "-raid" ] || [ "$1" = "-all" ]; then
gute_option=:
...
fi
...

if ! $gute_option; then
echo "Option $1 enthält Typo!" >&2
exit 1
fi
}

Das ist also i.W. das, was Du hattest in einer Funktionsdefinition
(in diesem Fall in einer Syntax, die mit allen Shells läuft), nur dass
für eine unbekannte Option ein Fehler ausgegeben und die weitere
Abarbeitung abgebrochen wird.

Dies solltest Dann für jedes Argument aufrufen.
Das ist sehr einfach:

for argument; do
haupttest "$argument"
done

Alternativ kannst Du das auch manuell so machen:

while [ $# -gt 0 ]; do
haupttest "$1"
shift
done
j***@schily.net
2021-02-14 14:34:38 UTC
Permalink
Post by Detlef Paschke
Irgend wo lese ich, dass so etwas mit "while getopts" gemacht werden
kann. Wie aber konkret, und ob es in meinem Fall geeignet ist...???
Doch, das geht mit getopts, allerdings kannst Du dann nicht mehr bash
verwenden, weil bash bei getopts lange nicht mehr state of the art ist.

Bash hat nämlich leider keine Unterstützung für lange Optionen.

GNU hat zwar Anfang der 1990er einen Parser für lange Optionen gebaut, aber
das war weder der erste Parser, noch war der gut geplant, oder kompatibel zum
Shell Builtin getopts(1), das auf getopt(3) aufbaut.

Lange Optionen (-lang) stammen übrigens von Multics (also ca. 1965) und die
erste vernünftige Implementierung eines Parsers für lange Optionen gab es 1980
auf dem ersten UNIX Clone UNOS mit getargs(). Das ist immer noch besser als
GNU getopt_long().

Anfang 1999 kam dann eine Erweiterung für getopt(3) in der libc von Solaris,
die kompatibel zur bisherigen Umgebung unter UNIX war. Dadurch unterstützt der
Bourne Shell seit 1999 auf Solaris lange Optionen (--lang) auch mit dem
getopts Builtin.

Als 2008 dann ksh93 in Solaris integriert wurde, wurde von David Korn
Kompatibilität verlangt und obwohl das komplett eigenständig implementiert
wurde, ist ksh93 kompatibel. Man lann daher dieses Konzept als das aktuell
einzig plattformübergreifende und kompatible System sehen.

getopts ":f:(file)(input-file)o:(output-file)"

unterstützt daher --file und --input-file als lange Aliase zu -f und
--output-file als langen Alias zu -o

Wenn mit dem aktuellen Bourne Shell

getopts ":()f:(file)(input-file)o:(output-file)"

verwendet wird, geht auch -file, -input-file und -output-file. Der aktuelle
Bourne Shell unterstützt übrigens auch lange Optionen ohne kurzen alias.
Siehe man page auf: http://schillix.sourceforge.net/man/man1/bosh.1.html

In Shell Syntax sähe das dann so aus:

getopts ":()f:(file)(input-file)o:(output-file)" OPT
do
case "$OPT" in

f)
infile="$OPTARG"
;;
o)
onfile="$OPTARG"
;;
?)
Usage "xxx"
exit 1
;;
esac

done
shift $(($OPTIND - 1))

echo "Remaining args: "$@"
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Helmut Waitzmann
2021-02-14 17:46:49 UTC
Permalink
Post by j***@schily.net
Post by Detlef Paschke
Irgend wo lese ich, dass so etwas mit "while getopts" gemacht
werden kann. Wie aber konkret, und ob es in meinem Fall geeignet
ist...???
Doch, das geht mit getopts, allerdings kannst Du dann nicht mehr
bash verwenden, weil bash bei getopts lange nicht mehr state of the
art ist.
Wer redet hier von «bash»? 
Post by j***@schily.net
Bash hat nämlich leider keine Unterstützung für lange Optionen.
POSIX‐getopts unterstützt auch keine langen Optionen.  Damit wäre
also auch POSIX‐getopts nicht mehr state of the art. 

Und nachdem Detlef nicht ausdrücklich geschrieben hat, dass sein
Shell‐Skript nicht auf allen zu POSIX kompatiblen Shells laufen
können muss, darf man in «de.comp.os.unix.shell» ruhig davon
ausgehen, dass er mit POSIX‐Inkompatibilitäten nicht rechnet. 
Post by j***@schily.net
GNU hat zwar Anfang der 1990er einen Parser für lange Optionen
gebaut, aber das war weder der erste Parser, noch war der gut
geplant, oder kompatibel zum Shell Builtin getopts(1), das auf
getopt(3) aufbaut.
Mir ist inzwischen bekannt, dass Du – wo sich die Gelegenheit
bietet – GNU schlechtredest.  So weit ich das sehe, ist Bash‐getopts
immerhin zu POSIX‐getopts kompatibel.  Oder irre ich mich da?  Dann
bin ich für Aufklärung darüber, wo POSIX‐getopts an den Utility
Syntax Guidelines
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02>
scheitert, dankbar. 

Aber hier geht es jetzt nicht um GNU‐getopts‐Implementierungen,
sondern darum, ein Shell‐Skript gewisse Optionen erkennen zu
lassen. 
Post by j***@schily.net
Lange Optionen (-lang) stammen übrigens von Multics (also ca. 1965)
und die erste vernünftige Implementierung eines Parsers für lange
Optionen gab es 1980 auf dem ersten UNIX Clone UNOS mit getargs().
Das ist immer noch besser als GNU getopt_long().
Das mag richtig sein.  Und – stell Dir vor – es hat auch niemand das
Gegenteil behauptet. 
Post by j***@schily.net
Anfang 1999 kam dann eine Erweiterung für getopt(3) in der libc von
Solaris, die kompatibel zur bisherigen Umgebung unter UNIX war.
Dadurch unterstützt der Bourne Shell seit 1999 auf Solaris lange
Optionen (--lang) auch mit dem getopts Builtin.
Als 2008 dann ksh93 in Solaris integriert wurde, wurde von David
Korn Kompatibilität verlangt
Passivformulierungen, in denen ein Objekt hinter der Präposition
«von» vorkommt, bergen immer das Risiko von Uneindeutigkeiten. 
Daher muss ich nachfragen:  Hat David Korn Kompatibilität verlangt
oder hat man von David Korn Kompatibilität verlangt? 

(Du scheinst Dich mit Computersprachen besser auszukennen als mit
natürlichen Sprachen.  Für «de.comp.os.unix.shell» sind aber beide
Fähigkeiten wichtig.) 
Post by j***@schily.net
und obwohl das komplett eigenständig implementiert wurde, ist ksh93
kompatibel. Man lann daher dieses Konzept als das aktuell einzig
plattformübergreifende und kompatible System sehen.
Leider ist es nicht auf allen POSIX‐Systemen von Haus aus
installiert.  Daher ist es ganz und gar nicht
plattformübergreifend. 

Nicht jeder, der Shell‐Skripte schreibt, kann einfach einen «ksh93»
oder Deinen «bosh» installieren.  Wenn der System‐Administrator da
nicht mitspielt, ist der Anwender geschnitten.  Gegen POSIX hingegen
wird sich ein Administrator eher nicht sperren, zumal
POSIX‐Kompatibilität heutzutage allermeist Standard sein dürfte. 

(Ja, ich weiß, dass beispielsweise auf Debian Buster Linux «dash»
nicht kompatibel zum POSIX‐Standard ist.  Deshalb ist auf dem
System, das ich administriere, «/bin/sh» nicht «/bin/dash».) 
Axel Reichert
2021-02-14 20:09:48 UTC
Permalink
Post by Helmut Waitzmann
Nicht jeder, der Shell‐Skripte schreibt, kann einfach einen «ksh93»
oder Deinen «bosh» installieren
[...]
Post by Helmut Waitzmann
auf Debian Buster Linux «dash» nicht kompatibel zum POSIX‐Standard
An dieser Stelle moechte ich gerne einhaken. Ueber etwa 25 Jahre habe
ich als Anwender mit csh, tcsh, zsh, bash und fish interaktiv
gearbeitet, Skripte geschrieben und IRIX-, Linux- oder FreeBSD-Systeme
in ganz kleinem Rahmen administriert. Die Grundzuege der Shell-Historie
kenne ich und weiss auch, dass Skripte gerne fuer "schlankere" Shells
("POSIX", /bin/sh, was immer sich dahinter im Detail verbirgt)
geschrieben werden.

Aber warum eigentlich? Ist die bessere Performance von dash oder bosh
(die ich jetzt einfach mal glaube, ohne mit diesen Shells Erfahrungen zu
haben) auf heutigen Systemen relevant? Dauern nicht die von den Shells
gestarteten Prozesse nicht Groessenordnungen laenger als das Starten
selbst? Wo ist der Overhead einer bash oder zsh da spuerbar?

Was spricht dagegen, z. B. init-Skripte oder sonstige admin-nahe Skripte
etwa in der fish zu schreiben? Ein "#!/bin/<shell nach wahl>" steht ja
sowieso in den Skripten. Und wenn ich einen She-bang verwende, warum
dann nicht eine mir als Admin genehme, womoeglich nicht POSIX-kompatible
Shell? Ist ein "bashism" auch mit She-bang noch ein Problem? Wenn ja,
warum?

Dies ist kein Trollversuch, sondern einfach nur die "rheinische
Sinnfrage" ("Wat sull dae janze Quatsch?") an deren Beantwortung ich
sehr interessiert bin.

Tschoe!

Axel
Martin Vaeth
2021-02-14 21:00:46 UTC
Permalink
Post by Axel Reichert
weiss auch, dass Skripte gerne fuer "schlankere" Shells
("POSIX", /bin/sh, was immer sich dahinter im Detail verbirgt)
geschrieben werden.
In der Praxis geht es weniger um Geschwindigkeit, sondern eher um
Wiederverwendbarkeit von z.T. ellenlangem Code.
Post by Axel Reichert
Ein "#!/bin/<shell nach wahl>" steht ja sowieso in den Skripten.
Solange Du sicher bist, dass diese Shell auf allen Systemen existiert
und die Shell ist, die Du "meinst" (etwa bei bash die richtige Version),
und solange Du sicher bist, dass Teile Deines Skripts nicht doch
irgendwann unter einer anderen Shell laufen müssen, ist das kein Problem.
Oft sind diese Voraussetzungen aber nicht gegeben oder nicht sicher
vorhersehbar.
Besonders heikel wird das durch die System-Shell, die z.T. von
Binärprogrammen ausgeführt wird, bei denen Du dann nicht am Shebang
drehen kannst.
Axel Reichert
2021-02-16 09:50:39 UTC
Permalink
Post by Martin Vaeth
Wiederverwendbarkeit von z.T. ellenlangem Code.
Sozusagen kleinster gemeinsamer Nenner, der einen Umstieg auf andere
Post by Martin Vaeth
Solange Du sicher bist, dass diese Shell auf allen Systemen existiert
und die Shell ist, die Du "meinst" (etwa bei bash die richtige
Version)
Gute Punkte, danke. Auch an Joerg fuer die Kommentare zur
Geschwindigkeit bei "configure" oder dem Booten (was beides bei mir
nicht so haeufig vorkommt).
Post by Martin Vaeth
und solange Du sicher bist, dass Teile Deines Skripts nicht doch
irgendwann unter einer anderen Shell laufen müssen, ist das kein Problem.
Ich sehe verschiedene Shells als verschiedene Programmiersprachen oder
zumindest verschiedene Dialekte der gleichen Sprache an. Damit ist doch
klar, dass ich nicht (beispielsweise) Code aus Common Lisp nach Scheme
ohne Aenderungen uebernehemen kann. Es ist also eine Abwaegung
erforderlich: Einfacheres Scripting mit einer Obermenge des
POSIX-Standards oder mehr Muehe beim ersten Schreiben ("kleinster
gemeinsamer Nenner"), dafuer kein Aufwand beim Portieren. Letzterer
Vorteil ist fuer mich privat irrelevant.
Post by Martin Vaeth
Besonders heikel wird das durch die System-Shell, die z.T. von
Binärprogrammen ausgeführt wird, bei denen Du dann nicht am Shebang
drehen kannst.
Was gibt es da an Beispielen? cron?

Tschoe!

Axel
j***@schily.net
2021-02-16 12:13:44 UTC
Permalink
Post by Axel Reichert
Ich sehe verschiedene Shells als verschiedene Programmiersprachen oder
zumindest verschiedene Dialekte der gleichen Sprache an. Damit ist doch
klar, dass ich nicht (beispielsweise) Code aus Common Lisp nach Scheme
ohne Aenderungen uebernehemen kann. Es ist also eine Abwaegung
erforderlich: Einfacheres Scripting mit einer Obermenge des
POSIX-Standards oder mehr Muehe beim ersten Schreiben ("kleinster
gemeinsamer Nenner"), dafuer kein Aufwand beim Portieren. Letzterer
Vorteil ist fuer mich privat irrelevant.
Wenn man POSIX als Basis nimmt, dann ist das eine Programmersprache in
unterschiedlich guten Implementierungen und es gibt Skripte in
unterschiedlicher Korrektheit was die strikte Einhaltung von Randbedingungen
angeht.

Was man auf keinen Fall vergessen sollte: Es gibt Dinge im POSIX Shell, die
sind nicht genau spezifiziert. Wer sich dabei auf das Verhalten eines
speziellen Shells verläßt (auch wenn das gut dokumentiert sein sollte), der
sollte sich darüber im Klaren sein, daß sein Skript nicht "strikt POSIX"
konform ist.

Dazu gehören selbst z.B. einfache Skripte, die auf eine bestimmte Abarbeitung
von Pipelines vertrauen.

echo bla | read VAR

funktioniert zwar in bosh und ksh, aber nicht in bash (es sei denn bash wurde
vorher umkonfiguriert/umgeschaltet) und natürlich auch nicht im historischen
Bourne Shell.

Wer will, kann dabei durchaus "strikt POSIX" konforme Skripte bauen, die auf
allen UNIX Systemen seit 2008 funktionieren. Man sollte aber auch wissen, daß
Solaris-10 einen historischen Bourne Shell als /bin/sh hat, obwohl Solaris-10
POSIX zertifiziert ist.

POSIX verlangt nämlich nicht, daß /bin/sh ein POSIX Shell ist. Vielmehr
bekommt man einen POSIX Shell durch:

PATH=`getconf PATH`
sh

Da POSIX bewußt keine Pfade außer /dev/null standardisiert. Daher ist

#!/path/to/shell

auch bewußt nicht im POSIX Standard, denn etwas wie

#!env sh

ist ein Sicherheitsrisiko. Es gäbe also keine Methode #!path sinnvoll im
Rahmen eines Standards zu nutzen der keine bestimmten Pfade festlegt.

Wer zu Shell-Unterschieden Hitergrundinformationen will, kann sich gerne die
Folien einer Vorlesung im Rahmen eines Admin-Seminars ansehen:

http://cdrtools.sourceforge.net/Files/Shell_ksh-2018.pdf

Man kann also durchaus auch Skripte schreiben, die mit allen Shells (außer
etwas wie csh oder fish) klarkommen.
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Axel Reichert
2021-02-16 15:19:47 UTC
Permalink
Post by j***@schily.net
Wenn man POSIX als Basis nimmt, dann ist das eine Programmersprache in
unterschiedlich guten Implementierungen
Aber die POSIX-Basis war ja gerade Ausgangspunkt meiner Sinnfrage:
Was bringt mir der kleinste gemeinsame Nenner? Deshalb habe ich hier
nach Vor- und Nachteilen gefragt.
Post by j***@schily.net
Wer will, kann dabei durchaus "strikt POSIX" konforme Skripte bauen,
die auf allen UNIX Systemen seit 2008 funktionieren.
Ja, und ich versuche abzuwaegen, ob sich das fuer mich (weitgehend im
Heimgebrauch) lohnt. Mit checkbashisms habe ich gerade festgestellt,
dass ich relativ wenig shell-spezifische Konstrukte verwende, allenfalls
mal

rm {foo,bar}.{a,b}

oder

paste <(foo ... | bar) <(baz ... | quux)
Post by j***@schily.net
#!env sh
ist ein Sicherheitsrisiko
Klar.
Post by j***@schily.net
http://cdrtools.sourceforge.net/Files/Shell_ksh-2018.pdf
Danke, habe ich schon kurz gesichtet, wie auch das Kapitel "Portable
Shell Programming" in der autoconf-Dokumentation.

Tschoe!

Axel
Martin Vaeth
2021-02-17 05:06:36 UTC
Permalink
Post by Axel Reichert
Post by Martin Vaeth
Besonders heikel wird das durch die System-Shell, die z.T. von
Binärprogrammen ausgeführt wird, bei denen Du dann nicht am Shebang
drehen kannst.
Was gibt es da an Beispielen? cron?
Init-Systeme wie openrc oder auch sysv, System-Kommando in
Programmiersprachen wie perl oder python, xdm & co. (~/.xinit*),
fvwm und andere konfigurierbare windows-manager.
Axel Reichert
2021-02-18 13:58:05 UTC
Permalink
Martin Vaeth <***@mvath.de> writes:

[Binaerprogramme, die die System-Shell starten]
Post by Martin Vaeth
Init-Systeme wie openrc oder auch sysv, System-Kommando in
Programmiersprachen wie perl oder python, xdm & co. (~/.xinit*),
fvwm und andere konfigurierbare windows-manager.
Alles klar, danke dir.

Tschoe!
j***@schily.net
2021-02-14 22:40:00 UTC
Permalink
Post by Axel Reichert
Aber warum eigentlich? Ist die bessere Performance von dash oder bosh
(die ich jetzt einfach mal glaube, ohne mit diesen Shells Erfahrungen zu
haben) auf heutigen Systemen relevant? Dauern nicht die von den Shells
gestarteten Prozesse nicht Groessenordnungen laenger als das Starten
selbst? Wo ist der Overhead einer bash oder zsh da spuerbar?
Also früher hatte ich auch geglaubt, daß bei einem "configure" Aurfuf die
meiste Zeit im Kompiler bleibt.

Dann habe ich eine eigene Messung durchgeführt und festgestellt, daß mit dem
ksh93 ein "configure" Lauf nur etwas mehr als die Hälfte der Zeit braucht, als
wenn man dies mit bash ausführt. Wer das nachmessen will, sollte wissen, daß
sich mein Meßergebnis auf das ksh93 Binary von OpenSolaris bezieht. Neuere
selbstkompilierte ksh93 Versionen sind zwar immer noch schneller als bash aber
merklich langsamer als das Binary von OpenSolaris, das konsequent auf den
Einsatz von shared Libs setzt und selbst den kompletten Shell in einer Shared
Library (libshell aus einem mini Main gerufen) hält.

Distros, die bewußt auf etwas Anderes als bash als /bin/sh setzen, machen dies
typischerweise, weil ihr System so merklich schneller bootet.
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
j***@schily.net
2021-02-14 23:06:24 UTC
Permalink
POSIX‐getopts unterstützt auch keine langen Optionen.  Damit wäre
also auch POSIX‐getopts nicht mehr state of the art. 
Wir haben schon über eine mögliche Einführung von langen Optionen bei einigen
Telefonkonferenzen diskutiert. Wenn das passiert, dann wird sicherlich eine
Lösung verwendet werden, die nicht singulär einem Hersteller zuzuordnen ist.
Mir ist inzwischen bekannt, dass Du – wo sich die Gelegenheit
bietet – GNU schlechtredest.  So weit ich das sehe, ist Bash‐getopts
immerhin zu POSIX‐getopts kompatibel.  Oder irre ich mich da?  Dann
bin ich für Aufklärung darüber, wo POSIX‐getopts an den Utility
Syntax Guidelines
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02>
scheitert, dankbar. 
Dir ist anscheinend nicht bekannt, daß das Problem das "GNU Projekt" selbst ist.
Software, die gemeldete Bugs Jahrzehtelang nicht fixt, kommt nicht gut 'rüber
und in diesem speziellen Fall war das eigentlich eine Randbemerkung zum größten
GNU Feind: Herrn Stallman, der mit seiner Hereinrederei vermutlich die Ursache
für diverse Probleme ist. Gerade bei langem Optionen ist Stallman ja religiös
motiviert.

Ich versuche nur darauf hinzuweisen, daß es neben GNU auch andere Quellen von
Software gibt, mit teilweise erkennbar besseren Konzepten.

Bash ist übrigens wegen der Verwendung von GNU getopt() nicht POSIX kompatibel,
es sei denn, die Environment Variable POSIXLY_CORRECT ist gesetzt.
Post by j***@schily.net
Als 2008 dann ksh93 in Solaris integriert wurde, wurde von David
Korn Kompatibilität verlangt
Passivformulierungen, in denen ein Objekt hinter der Präposition
«von» vorkommt, bergen immer das Risiko von Uneindeutigkeiten. 
Daher muss ich nachfragen:  Hat David Korn Kompatibilität verlangt
oder hat man von David Korn Kompatibilität verlangt? 
(Du scheinst Dich mit Computersprachen besser auszukennen als mit
natürlichen Sprachen.  Für «de.comp.os.unix.shell» sind aber beide
Fähigkeiten wichtig.) 
Wenn Dein Deutsch etwas besser wäre, dann würdest Du evt. wissen, daß die von
Dir fälschlich vermutete Interpretation des Satzes zu einer Formulierung in
der Form:

Als 2008 dann ksh93 in Solaris integriert wurde, wurde _durch_ David
Korn Kompatibilität verlangt...

geführt hätte.
--
EMail:***@schily.net Jörg Schilling D-13353 Berlin
Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Lesen Sie weiter auf narkive:
Loading...