Macro in Bash

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Macro in Bash

Beitrag von RobertDebiannutzer » 20.11.2018 14:07:55

Also folgendes Script funktioniert, wenn ich es mit "bash ./script.sh" starte. (Einfach nur ausführen geht ja nicht, weil dann kommt ja dash zum Zuge und versteht natürlich die enthaltenen bash-Spezialitäten nicht.) Auch "bash --posix ./script.sh" funktioniert seltsamerweise... Letzteres verstehe ich überhaupt nicht, denn dash z.B. kann mit "[[", associative arrays, "for ((..." und "if ((..." doch gar nix anfangen...

Code: Alles auswählen

#!/bin/sh

if [[ -d "$HOME" ]]; then
	declare -A num
	num=([eins]="one" [zwei]="two" [drei]="three")
	for ((i=0; i<3; i++)); do
		if ((i == 0)); then
			echo "${num[eins]}"
		elif ((i == 1)); then
			echo "${num[zwei]}"
		elif ((i == 2)); then
			echo "${num[drei]}"
		fi
	done
fi

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Macro in Bash

Beitrag von tobo » 20.11.2018 14:57:39

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
20.11.2018 14:07:55
Auch "bash --posix ./script.sh" funktioniert seltsamerweise... Letzteres verstehe ich überhaupt nicht, denn dash z.B. kann mit "[[", associative arrays, "for ((..." und "if ((..." doch gar nix anfangen...
Das ist nur Posix ähnlich - da sind noch genügend Bashism enthalten, die man in Skripten vermeiden sollte.
Verlinkt von man bash zum Parameter posix:
https://tiswww.case.edu/php/chet/bash/POSIX

r4pt0r
Beiträge: 1237
Registriert: 30.04.2007 13:32:44
Lizenz eigener Beiträge: MIT Lizenz

Re: Macro in Bash

Beitrag von r4pt0r » 20.11.2018 15:13:51

Wenn das script mit '#!/bin/sh' beginnt _muss_ es mit sh (bourne/posix shell oder eben dash im "sh-mode") ausgeführt werden. Alles andere wäre kein korrektes Verhalten, d.h. ein bug.
KA was bash mit einem /bin/sh script anstellt; aber 'bash script.sh' sieht in diesem Kontext irgendwie komplett verkehrt aus... bash sollte nur verwendet werden wenn es auch wirklich ein bash-script ist ('#!/bin/bash').

i.e.: wenn die entsprechende shell installiert ist (bourne shell / sh wie gesagt überall verfügbar), und die erste Zeile ein valides shebang enthält (#!/bin/sh), *muss* auch automatisch die entsprechende shell beim ausführen per "./script" verwendet werden.

Etliche tools (bzw meistens wrapper) in /usr/bin sind einfache shellscripte bzw man kann auch problemlos eigene scripte dort unterbringen (bzw korrekterweise eigentlich in /usr/local/bin), diese werden dann auch "direkt" aufgerufen und anhand des shebang die korrekte shell zum ausführen gestartet. Wir sind hier ja nicht bei Windows, das bis heute nur nach Dateiendungen schaut und die Hufe hochreißt wenn diese falsch ist :roll:

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Macro in Bash

Beitrag von tobo » 20.11.2018 15:30:56

Mit einer ersten Zeile "#!/bin/sh" im Skript, wird die Shell als Interpreter aufgerufen, die unter /bin/sh hinterlegt ist, sofern das Skript als ausführbare Datei gestartet wird (./script.sh). Das kann genauso die bash oder fish sein. Wird das Skript direkt am Interpreter (z.B. bash script.sh) gestartet, dann dann hat diese erste Zeile (Shebang) überhaupt keine Bedeutung.

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Macro in Bash

Beitrag von RobertDebiannutzer » 20.11.2018 15:47:51

ok, habe nun den symbolic link von /bin/sh geändert, zeigt nun auf nicht mehr auf /bin/dash, sondern auf /bin/bash.
Führe ich nun die Datei einfach mit "./script.sh" aus, wird sie nach wie vor korrekt interpretiert.
Somit ist m.E. widerlegt, dass
MSfree hat geschrieben: ↑ zum Beitrag ↑
20.11.2018 13:40:56
Allerdings bekommt die dash (oder auch die bash) über den ersten Aufrufparameter (hier /bin/sh) mit, daß sie sich wie eine sh verhalten soll.
Und obwohl in dem Link aus @tobos Beitrag steht...
When invoked as 'sh', Bash enters POSIX mode after reading the startup
files.
ist eben - wie @tobo schon sagte - der POSIX-Modus von bash nicht gleich das POSIX, was man vielleicht denkt...

Und das liegt möglicherweise auch daran, dass es - wie @owl102 sagte - keine "POSIX-Shell", nicht *die* "sh", gibt.

Am nahesten an das, was man sich unter "Posix-Kompatibilität" vorstellt, kommt da wohl dash - aus der manpage von dash:
dash is the standard command interpreter for the system. The current version of dash is in the process of being changed to conform with the POSIX 1003.2 and 1003.2a specifications for the shell. This version has many features
which make it appear similar in some respects to the Korn shell, but it is not a Korn shell clone (see ksh(1)). Only features designated by POSIX, plus a few Berkeley extensions, are being incorporated into this shell.

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Macro in Bash

Beitrag von tobo » 20.11.2018 17:31:23

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
20.11.2018 15:47:51
ok, habe nun den symbolic link von /bin/sh geändert, zeigt nun auf nicht mehr auf /bin/dash, sondern auf /bin/bash.
Führe ich nun die Datei einfach mit "./script.sh" aus, wird sie nach wie vor korrekt interpretiert.
Somit ist m.E. widerlegt, dass
MSfree hat geschrieben: ↑ zum Beitrag ↑
20.11.2018 13:40:56
Allerdings bekommt die dash (oder auch die bash) über den ersten Aufrufparameter (hier /bin/sh) mit, daß sie sich wie eine sh verhalten soll.
Und obwohl in dem Link aus @tobos Beitrag steht...
When invoked as 'sh', Bash enters POSIX mode after reading the startup
files.
Was in deinem Skript entspricht denn einem Punkt der Liste aus meinem Link und dürfte daher nicht funktionieren?
Teste:

Code: Alles auswählen

$ bash -c 'cat <(date)'
$ bash --posix -c 'cat <(date)'
Und dann schreibe mal "cat <(date)" als Zeile in dein Skript, aufgerufen über den umgebogenen Link. Stimmt schon, was da in der manpage steht. Die Einschränkung ist aber halt nicht Bash-Syntax, sondern das, was oben im Link gelistet ist.

owl102

Re: Macro in Bash

Beitrag von owl102 » 20.11.2018 18:53:02

Es ist doch ganz einfach:

- Benötigt man keine Kompatiblität zu anderen Shells außer der bash, ist es sinnvoll, bash-Skripte zu schreiben, die Features der bash nutzen. Sie machen den Code einfacher, lesbarer, robuster und wartbarer.

- Benötigt man Kompatiblität zu anderen Shells außer der bash, ist es sinnvoll, POSIX-Scripte zu schreiben.

Egal wie man sich entscheidet, auf beiden Seiten gewinnt man etwas und verliert etwas. Eine Entscheidung muß daher IMHO individuell gefällt werden.

Ich persönlich habe zum Beispiel nicht das Problem, daß irgendeines meiner Skripte auch plötzlich unter einem Illumos laufen können muß, wo keine bash installiert ist, ich keine root-Rechte habe (und sie somit auch nicht selber nachinstallieren kann), und der Admin auch keine bash installieren mag.

Aber eigentlich betrifft das Problem alle Programmiersprachen, die sich im Laufe der Jahre weiterentwickeln, C, C++, Java, Perl, Python, ... Welche Version des Standards benutzt man hier?

Im Falle des POSIX-Standards hat man sogar noch ein weiteres Problem: Der POSIX-Standard ist an vielen Stellen schwammig. Selbst wenn man "#!/bin/sh" schreibt und keine Bashisms verwendet, kann es sehr gut sein, daß das Skript in einer anderen Umgebung/Shell nicht wie erwartet funktioniert. Beispiel "echo": Es ist lediglich spezifiziert, daß es Zeichenketten + Zeichenumbruch ausgibt. Verhalten bei Sequenzen mit Backslash am Anfang, wie z.B. "\t"? AFAIK nicht durch POSIX gedeckt, kann so oder so sein. [1] Schalter "-n" vorhanden? AFAIK nicht durch POSIX gedeckt. (Deswegen hier am besten immer printf statt echo verwenden.) Wird bei "xxx | ... <Schleife>" intern eine Subshell gestartet oder nicht, d.h. sind dort gesetzte Variablen auch am Ende der Schleife noch vorhanden? Nach meinem Kenntnisstand läßt POSIX dies offen, d.h. das kann jede Shell so machen wie sie mag. [2] Und so weiter... Bei bash hingegen hat man nur bei anderen Versionen der bash ggf. ein anderes Verhalten, und diese Dinge sind sowohl übersichtlich als auch konkret dokumentiert.

Und dann ist POSIX auch nicht gleich POSIX, auch hier gibt es unterschiedliche Versionen des Standards. Wenn man sich für POSIX entscheidet, welche Version des Standards nimmt man?

[1] Quelle: http://mywiki.wooledge.org/Bashism
[2] Quelle: http://mywiki.wooledge.org/BashFAQ/024

Benutzeravatar
Lohengrin
Beiträge: 3227
Registriert: 29.08.2004 00:01:05
Wohnort: Montsalvat

Re: Macro in Bash

Beitrag von Lohengrin » 20.11.2018 22:41:37

Faszinierend!
Ich habe bei meiner Programmiererei in Bash nie so etwas wie ${!ameise} gebraucht, wusste nur, dass das woanders geht, und wollte wissen, wie es geht.
Und nun stelle ich fest, dass Posix sehr unkonkret ist. Ich habe den Eindruck, dass die große Mehrheit der unixartigen Betriebssysteme GNU/Linux sind, und dass es auf denen Bash gibt, aber kein Bourne. Da fällt mir die Auswahl bzgl Kompatibilität leicht.
Harry, hol schon mal das Rasiermesser!

raa
Beiträge: 411
Registriert: 19.12.2013 10:16:19

Re: Macro in Bash

Beitrag von raa » 21.11.2018 00:42:37

Mal ehrlich: Welcher Kaputte außer mir programmiert denn noch auf Shell-Ebene? :wink:
RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
19.11.2018 19:13:44
Funktionen gibt's ja auch noch...
Gott sei Dank auch. Irgendwann hab' ich also mal angefangen, die kryptischen Befehle (die ich mir nie im Leben merken kann und will), als Funktionen in private "Libraries" zu verpacken. Es ist wohl ein Unterschied, ob man jedesmal sowas konstruieren muss:

Code: Alles auswählen

echo "$str" | sed -e "s/"$strLeftMarg"[^<>]*"$strRightMarg"/"$strSub"/g; /^[ ]*$/d" 
Oder einfach aus dem Katalog kopiert:

Code: Alles auswählen

# Jeden Teilstring von $strLeftMarg bis $strRightMarg ersetzen
strRep=$(replPartStrings "$str" "$strLeftMarg" "$strRightMarg" "$strSub")
(Funzt übrigens sowohl mit Strings als auch mit Dateien, klar.) Damit macht's also richtig Spaß, wenn auch (oder gerade weil) jetzt meine Scripte größtenteils nur noch entfernte Ähnlichkeit mit Shellscripten haben, schon eher nach einer höheren Sprache aussehen. :wink:

Benutzeravatar
Lohengrin
Beiträge: 3227
Registriert: 29.08.2004 00:01:05
Wohnort: Montsalvat

Re: Macro in Bash

Beitrag von Lohengrin » 21.11.2018 01:18:24

raa hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 00:42:37
Irgendwann hab' ich also mal angefangen, die kryptischen Befehle (die ich mir nie im Leben merken kann und will), als Funktionen in private "Libraries" zu verpacken. Es ist wohl ein Unterschied, ob man jedesmal sowas konstruieren muss:

Code: Alles auswählen

echo "$str" | sed -e "s/"$strLeftMarg"[^<>]*"$strRightMarg"/"$strSub"/g; /^[ ]*$/d" 
Die $strLeftMarg, $strRightMarg und $strSub sind nackt. Wenn die Leerzeichen oder Tab drin haben, hast du ein Problem.

Ansonsten richtig so! Jedenfalls in der Theorie.
Wenn ich zwei mal das gleiche Kompliziertere brauche, ist es Zeit für eine Funktion. Dann hat man (so wie jetzt du) nämlich mögliche Fehler an derselben Stelle. Nur wenn ich die beiden zurechtbiegen muss, damit sie dieselbe Funktion benutzen können, kann es sein, dass die Biegerei aufwendiger ist als der Vorteil durch die Funktion.

Leider habe ich das bei meinem letzten Werk verbaselt. Da steht

Code: Alles auswählen

 47      $hash_prog | cut -f1 -d\  | xxd -r -p | base64 -w0 | tr -d '='
159  salzlaenge=$($hash_prog < /dev/null | cut -f1 -d\ | xxd -r -p | wc -c)
167      x=$(head -c $salzlaenge < /dev/urandom | base64 -w0)
Und dann ist mir das auf die Füße gefallen.

Einer mit BSD, der es ausprobiert hat, hat bei seinem base64 die Option -w nicht. der musste dann von base64 -w0 | tr -d '=' umstellen auf base64 | tr -d '=\n'. Der hat den Fehler natürlich nochmal gehabt, nachdem er es schon repariert hatte.
raa hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 00:42:37
Damit macht's also richtig Spaß, wenn auch (oder gerade weil) jetzt meine Scripte größtenteils nur noch entfernte Ähnlichkeit mit Shellscripten haben, schon eher nach einer höheren Sprache aussehen. :wink:
Bei mir ist es umgekehrt.
Ich mag if A ; then B ; else C ; fi nicht. Das ist mir zu hochsprachig. Ich bevorzuge A && B || C. Leider muss ich mir da sicher sein, dass B 0 zurückgibt, sonst muss es A && { B ; true ; } || C heißen, was mir aber immernoch viel besser gefällt als das Hochsprachige. Ist doch schon fast so hübsch wie A?B:C.
Harry, hol schon mal das Rasiermesser!

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Macro in Bash

Beitrag von RobertDebiannutzer » 21.11.2018 09:52:04

Was man vielleicht bezüglich bash vs. dash noch erwähnen könnte, ist, dass dash schneller sein kann. Also je nach Aufgabe natürlich. Das kann auch mal ganz nützlich sein. Also wenn man jetzt immer mal wieder ein kleines Mini-Script für irgendwas startet, dann würde ich das eher für dash schreiben.
Für etwas, was mehr "sophisticated" ist, immer bash.
Was auch bei Funktionen in bash toll ist, ist, dass sie Argumente annehmen können.

BTW: Den Rekord des schlimmsten Shell-Scripts aller Zeiten beanspruche eh ich...
Mal ein Auszug aus einem ganz schlimmen Script, das ich früher mal schrieb:

Code: Alles auswählen

[...]
for ((q=1; q<=4; q++)); do
	if (( q == 1 )); then
		TEST
		tput cup $(($(($((q-1))*2*QUANT+1+q-y))*x)) 0
		for ((l=1; l<=QUANT; l++)); do
			echo $(echo -e "${NUM[$l]}\n" &)
		done
		for ((l=2; l<=QUANT; l++)); do
			if (( l <= 3 )); then
				for ((i=$((l-1)); i>=$((l-$((l-1)))); i--)); do
					TEST
					tput cup $(($(($((l*2-1-$((l-i))))+$((q-1))*2*QUANT+q-y))*x)) $(($((l-i))*$((2+QUANTC))))
					echo $(echo "${NUM[$l]}-${NUM[$i]}" | bc &)
				done
			else
				for ((i=$((l-1)); i>=$((l-3)); i--)); do
					TEST
					tput cup $(($(($((l*2-1-$((l-i))))+$((q-1))*2*QUANT+q-y))*x)) $(($((l-i))*$((2+QUANTC))))
					echo $(echo "${NUM[$l]}-${NUM[$i]}" | bc &)
				done
			fi
		done
	elif (( q == 2 )); then
[...]
oder das:

Code: Alles auswählen

[...]
countalign3=$(($(printf "%s\n" ${zielspalte[@]} | wc -L)+1))
if (( countalign2 <= countalign3 )); then countalignmax=$countalign3; else countalignmax=$countalign2; fi

for ((l=1; l<=count; l++)); do
	for ((i=1; i<=indent; i++)); do printf "%s" " "; done
	printf "%s" "| " && printf "%s\n" ${line2[l]} | while read number; do printf %"$countalignmax"s "$number"; done
	if (( l == 1 )); then printf "%s" "    (2. Matrix)"; fi
	printf "\n"
done

count3=$((countalignmax*$(wc -w <<< ${line2[1]})+countalign*count+5))
for ((i=1; i<=count3; i++)); do printf "%s" "–"; done && printf "\n"

for ((l=1; l<=lines; l++)); do
	printf "%s\n" ${line[l]} | while read number; do printf %"$countalign"s "$number"; done && printf "%s" "  | "
	printf "%s\n" ${zielzeile[l]} | while read number; do printf %"$countalign3"s "$number"; done
	if (( l == 1)); then printf "%s\n" "    (Ergebnis)"; else printf "\n"; fi
done
printf "\n"
(Das eine war der Versuch eines Scriptes zum Lösen von diesen dusseligen Zahlenreihen - also z.B. "was ist das Muster in '1 3 2 6 3 9'?" -, das andere war ein Script zur Matrizenmultiplikation...)

Benutzeravatar
Meillo
Moderator
Beiträge: 8781
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Macro in Bash

Beitrag von Meillo » 21.11.2018 11:27:00

owl102 hat geschrieben: ↑ zum Beitrag ↑
20.11.2018 18:53:02
Es ist doch ganz einfach:

- Benötigt man keine Kompatiblität zu anderen Shells außer der bash, ist es sinnvoll, bash-Skripte zu schreiben, die Features der bash nutzen. Sie machen den Code einfacher, lesbarer, robuster und wartbarer.
Man kann das so sehen oder anders. Ich finde, das ist wie mit C und C++, manchmal ist zweiteres besser (im Sinne von einfacher, lesbarer, robuster, wartbarer), aber nicht immer. Manchmal laesst sich das objektiv feststellen, manches haengt mehr an persoenlichen Erwartungen, Vorlieben, Prioritaeten.

Aber ja: Wenn man keine Kompatiblitaet braucht, dann kann man verwenden, was einem selbst am sinnvollsten erscheint. So gesehen stimme ich dir zu.
- Benötigt man Kompatiblität zu anderen Shells außer der bash, ist es sinnvoll, POSIX-Scripte zu schreiben.

Egal wie man sich entscheidet, auf beiden Seiten gewinnt man etwas und verliert etwas. Eine Entscheidung muß daher IMHO individuell gefällt werden.
Ja.

Im Falle des POSIX-Standards hat man sogar noch ein weiteres Problem: Der POSIX-Standard ist an vielen Stellen schwammig. Selbst wenn man "#!/bin/sh" schreibt und keine Bashisms verwendet, kann es sehr gut sein, daß das Skript in einer anderen Umgebung/Shell nicht wie erwartet funktioniert. Beispiel "echo": Es ist lediglich spezifiziert, daß es Zeichenketten + Zeichenumbruch ausgibt. Verhalten bei Sequenzen mit Backslash am Anfang, wie z.B. "\t"? AFAIK nicht durch POSIX gedeckt, kann so oder so sein. [1] Schalter "-n" vorhanden? AFAIK nicht durch POSIX gedeckt. (Deswegen hier am besten immer printf statt echo verwenden.) Wird bei "xxx | ... <Schleife>" intern eine Subshell gestartet oder nicht, d.h. sind dort gesetzte Variablen auch am Ende der Schleife noch vorhanden? Nach meinem Kenntnisstand läßt POSIX dies offen, d.h. das kann jede Shell so machen wie sie mag. [2] Und so weiter... Bei bash hingegen hat man nur bei anderen Versionen der bash ggf. ein anderes Verhalten, und diese Dinge sind sowohl übersichtlich als auch konkret dokumentiert.

Und dann ist POSIX auch nicht gleich POSIX, auch hier gibt es unterschiedliche Versionen des Standards. Wenn man sich für POSIX entscheidet, welche Version des Standards nimmt man?
Als Ergaenzung: Man muss POSIX korrekt verstehen. Sein Ziel war, ausgehend von den Zeiten der sogenannten Unix-Kriege, die Gemeinsamkeiten der verschiedenen Unix-Systeme zu dokumentieren. Es ging bei POSIX also nicht darum, Verhalten zu *definieren*, sondern darum Verhalten zu *dokumentieren*. Insofern unterscheidet sich POSIX von anderen Standards. Nicht definiertes Verhalten ist bei POSIX kein Fehler sondern eine Notwendigkeit. Aus diesen Gruenden kann POSIX manches schlichtweg nicht leisten, was manchmal von ihm erwartet wird.

POSIX hilft dabei, groessere Portabilitaet zu erreichen, aber es kann ueberhaupt nichts garantieren. (Viele sich als POSIX-kompatibel bezeichnenden Programme sind ueberhaupt nicht vollstaendig POSIX-kompatibel.)

Wenn man garantierte Kompatibilitaet haben will, dann muss man gegen eine bestimmte Version einer bestimmten Shell mit bestimmten Build-Parametern entwickeln und diese Shell dann als Abhaengigkeit voraussetzen.

Es kommt also immer darauf an, wie man die Dinge betrachtet. Diese etwas andere Perspektive auf die durchaus korrekten Aussagen wollte ich ergaenzen.
Use ed once in a while!

owl102

Re: Macro in Bash

Beitrag von owl102 » 21.11.2018 18:40:55

Meillo hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 11:27:00
Aber ja: Wenn man keine Kompatiblitaet braucht, dann kann man verwenden, was einem selbst am sinnvollsten erscheint.
Das hört sich so an, als könnte man sich nur dann für die Bash entscheiden, wenn man keine Kompatibilität benötigt.

Aber auch ich will Kompatibilität; meine Skripte sollen unter RHEL/CentOS 7, Fedora, Debian 9 und openSuse laufen, und einige auch auf meinem Illumos-basiertem Server (OmniOS). Und deswegen habe ich mich bewußt für "!/bin/bash" entschieden.

Wie man sieht: Eine individuelle Entscheidung, basierend auf der Kompatibilität, die ich benötige. Deswegen störe ich mich auch immer an Sätzen wie "Und für höhere portabilität kein bash sondern bourne shell verwenden...", denn ohne zu wissen, was für Kompatibilität der Autor/Fragestellung überhaupt benötigt ist so ein Ratschlag IMHO einfach Käse. (Und "bourne shell verwenden" bedeutet, nicht einmal POSIX einsetzen zu dürfen, da die Bourne Shell einige POSIX-Features nicht bietet, wie z.B. "test -e" oder "test -L". [1] Aber der Autor dieser Zeile hat auch recht, man wäre dann zu noch mehr/älteren Unix-Systemen kompatibel, als wenn man POSIX einsetzen würde.)

[1] Quelle: http://mywiki.wooledge.org/BashFAQ/004

raa
Beiträge: 411
Registriert: 19.12.2013 10:16:19

Re: Macro in Bash

Beitrag von raa » 21.11.2018 22:09:19

Lohengrin hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 01:18:24
raa hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 00:42:37
Irgendwann hab' ich also mal angefangen, die kryptischen Befehle (die ich mir nie im Leben merken kann und will), als Funktionen in private "Libraries" zu verpacken. Es ist wohl ein Unterschied, ob man jedesmal sowas konstruieren muss:

Code: Alles auswählen

echo "$str" | sed -e "s/"$strLeftMarg"[^<>]*"$strRightMarg"/"$strSub"/g; /^[ ]*$/d" 
Die $strLeftMarg, $strRightMarg und $strSub sind nackt. Wenn die Leerzeichen oder Tab drin haben, hast du ein Problem.
Nein. (Schon ...zigmal getestet.) Der Fallstrick lauert woanders, bei '.' und '/' - Abhilfe:

Code: Alles auswählen

# Achtung: Punkte in "$strPartRep" maskieren: '\\.', sonst werden sie als Platzhalter interpretiert
# Option: Steuerzeichen, das im String nicht vorkommt (default: '/')
Na, und so weiter ... :wink:
Lohengrin hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 01:18:24
Ansonsten richtig so! Jedenfalls in der Theorie.
Wenn ich zwei mal das gleiche Kompliziertere brauche, ist es Zeit für eine Funktion. Dann hat man (so wie jetzt du) nämlich mögliche Fehler an derselben Stelle. Nur wenn ich die beiden zurechtbiegen muss, damit sie dieselbe Funktion benutzen können, kann es sein, dass die Biegerei aufwendiger ist als der Vorteil durch die Funktion.
Dann muss man also die Funktion "zurechtbiegen", s.o.

Benutzeravatar
Lohengrin
Beiträge: 3227
Registriert: 29.08.2004 00:01:05
Wohnort: Montsalvat

Re: Macro in Bash

Beitrag von Lohengrin » 21.11.2018 23:13:53

raa hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 22:09:19
Lohengrin hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 01:18:24
Die $strLeftMarg, $strRightMarg und $strSub sind nackt. Wenn die Leerzeichen oder Tab drin haben, hast du ein Problem.
Nein. (Schon ...zigmal getestet.) Der Fallstrick lauert woanders, bei '.' und '/' - Abhilfe:
Dann vermute ich, dass es bei dir in der Funktion so aussieht, und die $1 $2 $3 $4 in in Gänsefüßen sind.

Code: Alles auswählen

replPartStrings () {
    echo "$1" | sed -e "s/$2[^<>]*$3/$4"/g; /^[ ]*$/d"
}
raa hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 22:09:19

Code: Alles auswählen

# Achtung: Punkte in "$strPartRep" maskieren: '\\.', sonst werden sie als Platzhalter interpretiert
# Option: Steuerzeichen, das im String nicht vorkommt (default: '/')
Du kannst auch die Variablen, bevor sie ins Monster gesetzt werden, bearbeiten

Code: Alles auswählen

local a b c
a=$(echo -n "$2" | sed 's/\//\\\//g; s/\./\\\./g' )
b=$(echo -n "$3" | sed 's/\//\\\//g; s/\./\\\./g' )
c=$(echo -n "$4" | sed 's/\//\\\//g; s/\./\\\./g' )
echo "$1" | sed -e "s/$a[^<>]*$b/$c/g; /^[ ]*$/d"
Wobei du dann natürlich wieder eine Funktion für die drei gleichen Zeilen machen könntest.
Harry, hol schon mal das Rasiermesser!

owl102

Re: Macro in Bash

Beitrag von owl102 » 21.11.2018 23:25:59

Lohengrin hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 23:13:53

Code: Alles auswählen

    echo "$1" | sed -e "s/$2[^<>]*$3/$4"/g; /^[ ]*$/d"
Wenn man bash benutzt, kann man auch "here strings" benutzen:

Code: Alles auswählen

 sed ... <<< "$1"
Und wenn man kein bash, sondern POSIX benutzt, sollte man "echo "$1"" nicht als generischen Input verwenden, da es sein kann, daß das echo der Shell Dinge innerhalb der Zeichenkette interpretiert. Stattdessen besser "printf "%s\n" "$1" verwenden.

Benutzeravatar
Lohengrin
Beiträge: 3227
Registriert: 29.08.2004 00:01:05
Wohnort: Montsalvat

Re: Macro in Bash

Beitrag von Lohengrin » 21.11.2018 23:33:52

owl102 hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 23:25:59
Wenn man bash benutzt, kann man auch "here strings" benutzen:

Code: Alles auswählen

 sed ... <<< "$1"
Ja. Ist ganz nett. Aber ich ärgere mich über Emacs. Sobald ich << getippt habe, haut der mit zwei EOF da hin und setzt den Curor dazwischen. Das muss ich dann erst wieder wegmachen.
owl102 hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 23:25:59
Und wenn man kein bash, sondern POSIX benutzt, sollte man "echo "$1"" nicht als generischen Input verwenden, da es sein kann, daß das echo der Shell Dinge innerhalb der Zeichenkette interpretiert. Stattdessen besser "printf "%s\n" "$1" verwenden.
Das war mir vorgestern noch nicht klar. Danke für den Hinweis! Ich werde es in Erinnerung behalten.
Harry, hol schon mal das Rasiermesser!

raa
Beiträge: 411
Registriert: 19.12.2013 10:16:19

Re: Macro in Bash

Beitrag von raa » 22.11.2018 08:51:46

Lohengrin hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 23:13:53
raa hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 22:09:19
Lohengrin hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 01:18:24
Die $strLeftMarg, $strRightMarg und $strSub sind nackt. Wenn die Leerzeichen oder Tab drin haben, hast du ein Problem.
Nein. (Schon ...zigmal getestet.) Der Fallstrick lauert woanders, bei '.' und '/' - Abhilfe:
Dann vermute ich, dass es bei dir in der Funktion so aussieht, und die $1 $2 $3 $4 in in Gänsefüßen sind.

Code: Alles auswählen

replPartStrings () {
    echo "$1" | sed -e "s/$2[^<>]*$3/$4"/g; /^[ ]*$/d"
}
So etwa. :wink: In der Library:

Code: Alles auswählen

# Teilstring "$strPart" durch "$strPartRep" ersetzen
# Achtung: Punkte in "$strPartRep" maskieren: '\\.', sonst werden sie als Platzhalter interpretiert
# Option: Steuerzeichen, das im String nicht vorkommt (default: '/')
replChars () { #RV strRep #A "$str" "$strPart" "$strPartRep" 'optChrCtrl'

	chrCtrl=/; [ $4 ] && chrCtrl=$4
	echo "$1" | sed s"$chrCtrl$2$chrCtrl$(maskSpecChars "$3")$chrCtrl"g
}
Im Katalog sieht das dann so aus:

http://hkraus.eu/replChars.png

maskSpecChars () (Sonderzeichen '\' '&' maskieren) ist natürlich auch eine Funktion ... Frag' mich also mal, warum ich nicht auch aus "Punkte maskieren" eine gemacht habe. Wem das gelingt, der möge sich bitte melden. :wink:

Der Vollständigkeit halber: Die erste Zeile in meinen Scripten lautet selbstverständlich immer

Code: Alles auswählen

#!/bin/bash
;)

Benutzeravatar
Meillo
Moderator
Beiträge: 8781
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Macro in Bash

Beitrag von Meillo » 22.11.2018 09:32:47

owl102 hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 18:40:55
Meillo hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 11:27:00
Aber ja: Wenn man keine Kompatiblitaet braucht, dann kann man verwenden, was einem selbst am sinnvollsten erscheint.
Das hört sich so an, als könnte man sich nur dann für die Bash entscheiden, wenn man keine Kompatibilität benötigt.

Aber auch ich will Kompatibilität; meine Skripte sollen unter RHEL/CentOS 7, Fedora, Debian 9 und openSuse laufen, und einige auch auf meinem Illumos-basiertem Server (OmniOS). Und deswegen habe ich mich bewußt für "!/bin/bash" entschieden.

Wie man sieht: Eine individuelle Entscheidung, basierend auf der Kompatibilität, die ich benötige. Deswegen störe ich mich auch immer an Sätzen wie "Und für höhere portabilität kein bash sondern bourne shell verwenden...", denn ohne zu wissen, was für Kompatibilität der Autor/Fragestellung überhaupt benötigt ist so ein Ratschlag IMHO einfach Käse. (Und "bourne shell verwenden" bedeutet, nicht einmal POSIX einsetzen zu dürfen, da die Bourne Shell einige POSIX-Features nicht bietet, wie z.B. "test -e" oder "test -L". [1] Aber der Autor dieser Zeile hat auch recht, man wäre dann zu noch mehr/älteren Unix-Systemen kompatibel, als wenn man POSIX einsetzen würde.)

[1] Quelle: http://mywiki.wooledge.org/BashFAQ/004
Gut, dass du nachhakst. Ich habe es nicht so gemeint wie es sich scheinbar auch anhoeren koennte. Im Gegenteil, ich stimme allen deinen Aussagen in diesem Post zu. :-)
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8781
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Macro in Bash

Beitrag von Meillo » 22.11.2018 09:34:04

raa hat geschrieben: ↑ zum Beitrag ↑
22.11.2018 08:51:46
Der Vollständigkeit halber: Die erste Zeile in meinen Scripten lautet selbstverständlich immer

Code: Alles auswählen

#!/bin/bash
;)
Sollte sie nicht vielleicht besser

Code: Alles auswählen

#!/usr/bin/env bash
lauten? ;-)
Use ed once in a while!

raa
Beiträge: 411
Registriert: 19.12.2013 10:16:19

Re: Macro in Bash

Beitrag von raa » 22.11.2018 09:57:54

Meillo hat geschrieben: ↑ zum Beitrag ↑
22.11.2018 09:34:04
raa hat geschrieben: ↑ zum Beitrag ↑
22.11.2018 08:51:46
Der Vollständigkeit halber: Die erste Zeile in meinen Scripten lautet selbstverständlich immer

Code: Alles auswählen

#!/bin/bash
;)
Sollte sie nicht vielleicht besser

Code: Alles auswählen

#!/usr/bin/env bash
lauten? ;-)
Klar, man kann's auch übertreiben.

raa
Beiträge: 411
Registriert: 19.12.2013 10:16:19

Re: Macro in Bash

Beitrag von raa » 22.11.2018 10:11:26

owl102 hat geschrieben: ↑ zum Beitrag ↑
21.11.2018 23:25:59
Und wenn man kein bash, sondern POSIX benutzt, sollte man "echo "$1"" nicht als generischen Input verwenden, da es sein kann, daß das echo der Shell Dinge innerhalb der Zeichenkette interpretiert.
Och, die bash ist auch äußerst interpretationsfreudig. :wink: Aber bei

Code: Alles auswählen

echo $irgendeinString | sed  sonstwas
interpretiert erst sed, kannste mir glauben.

Code: Alles auswählen

echo $irgendeinString
liefert allerdings an Stelle mehrerer aufeinanderfolgender Blanks jeweils nur eins, jedenfalls bei mir ...

owl102

Re: Macro in Bash

Beitrag von owl102 » 22.11.2018 10:16:33

raa hat geschrieben: ↑ zum Beitrag ↑
22.11.2018 09:57:54
Klar, man kann's auch übertreiben.
Ich empfinde das als einen guten und berechtigten Punkt und nicht als Übertreibung.

Ist auch in [1] und [2] zu finden. Dort findet sich übrigens auch ein IMHO guter Abschnitt "Choose Your Shell".

[1] http://mywiki.wooledge.org/BashGuide/Practices
[2] http://mywiki.wooledge.org/BashProgramming

Benutzeravatar
Meillo
Moderator
Beiträge: 8781
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Macro in Bash

Beitrag von Meillo » 22.11.2018 10:22:39

raa hat geschrieben: ↑ zum Beitrag ↑
22.11.2018 10:11:26

Code: Alles auswählen

echo $irgendeinString
liefert allerdings an Stelle mehrerer aufeinanderfolgender Blanks jeweils nur eins, jedenfalls bei mir ...
Das ist auch korrekt so. Ist jedem (der Nicht-Profis) klar, warum das so ist?

... und es zeigt schoen, warum es sinnvoll ist, Variablenexpansionen normalerweise zu doublequoten.
Use ed once in a while!

raa
Beiträge: 411
Registriert: 19.12.2013 10:16:19

Re: Macro in Bash

Beitrag von raa » 22.11.2018 12:35:07

owl102 hat geschrieben: ↑ zum Beitrag ↑
22.11.2018 10:16:33
raa hat geschrieben: ↑ zum Beitrag ↑
22.11.2018 09:57:54
Klar, man kann's auch übertreiben.
Ich empfinde das als einen guten und berechtigten Punkt und nicht als Übertreibung.
Ich schon. Was ist denn der Unterschied? "Weiß" das OS sonst nicht, dass es als Umgebung für das Script eine Instanz der bash starten muss?

Antworten