Richtige Nutzung von sed

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Knogle
Beiträge: 466
Registriert: 06.05.2016 19:29:00
Lizenz eigener Beiträge: MIT Lizenz

Richtige Nutzung von sed

Beitrag von Knogle » 15.12.2018 19:57:45

Ich gruesse euch liebe Community.
Ich habe aktuell ein Script von meinem uralt Server uebernommen und angepasst.
Jedoch komme ich da mit sed nicht ganz klar.
Ich will hier einen Inhalt einer Datei mit Strings ersetzen, jedoch meckert er wenn ich die SERVER1-4 Strings einsetze, und meldet einen nicht beendeten s Befehl.
Wie behebe ich das Problem?

Hier ist mein Script.

Code: Alles auswählen

#!/bin/bash
sleep 5
echo "/etc/init.d/minecraft_universal start ftb_continuum_last"
echo "/etc/init.d/minecraft_universal start ftb_continuum"


SERVER1=$(/etc/init.d/minecraft_universal start ftb_continuum_last) 
SERVER2=$(/etc/init.d/minecraft_universal start ftb_continuum)

 




#if [ "$(id -u)" != "0" ]; then
#  exec sudo "$0" "$@"
#fi



cp /etc/mc/header.html.bak ~/header.html

MYHOSTNAME=$(hostname);
DATUM=$(date +%d.%m.%y);
ZEIT=$(date +%H:%M);
TEXT=$(motivate);
sed -i "s/TEXTHERE/Services gestartet auf $MYHOSTNAME am $DATUM um $ZEIT\nServer: \n($SERVER1) \n($SERVER2) /g" ~/header.html
awk -i inplace -v input="$TEXT" 'NR == 1, /MOTIVATION/ { sub(/MOTIVATION/, input) } 1' ~/header.html
mail -a "Content-type: text/html;" -s "Minecraft Services gestartet am $DATUM um $ZEIT" user@test < ~/header.html
rm ~/header.html
beep -f 600 -l 100

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

Re: Richtige Nutzung von sed

Beitrag von RobertDebiannutzer » 15.12.2018 21:46:33

Ich vermute, dass es daran liegt, dass in Deinen Variablen SERVER1 und SERVER2 newlines aus der Ausgabe der Befehle gespeichert werden.

Knogle
Beiträge: 466
Registriert: 06.05.2016 19:29:00
Lizenz eigener Beiträge: MIT Lizenz

Re: Richtige Nutzung von sed

Beitrag von Knogle » 15.12.2018 22:19:34

Ok danke! Habe nicht gedacht dass es an den Newlines liegt.
Gibt es einen guten Weg die zu escapen? Weil ich habe nun einige Dinge probiert, bekomme nun aber sowas hier raus als Fehler.

ftb_continuum.jar: Kommando nicht gefunden.

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

Re: Richtige Nutzung von sed

Beitrag von RobertDebiannutzer » 15.12.2018 22:29:02

Das weiß ich gerade nicht, wie man das elegant und verlässlich machen kann. Aber warum hängst Du den Ouptut nicht einfach nach dem sed-Kommando mit echo ran (als Alternative, auch wenn dann das mit dem Ersetzen nicht klappt)? Also so:

Code: Alles auswählen

echo "$SERVER1" >> ~/header.html
echo "$SERVER2" >> ~/header.html
Das sollte auf jeden Fall funktionieren. Aber wichtig: Beachte das ">>", damit der output von echo an die Datei angehängt wird und nicht der Inhalt der Datei durch den output *ersetzt* wird. Gegebenenfalls musst Du in der manpage Deiner Shell nach der richtigen Syntax für "Appending Redirected Output" oder so nachschauen. Aber bei bash oder dash in der Version, in der sie jeweils für Debian 9 vorliegen, funktioniert das so mit dem ">>".

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

Re: Richtige Nutzung von sed

Beitrag von Lohengrin » 16.12.2018 07:17:06

Knogle hat geschrieben: ↑ zum Beitrag ↑
15.12.2018 22:19:34
Ok danke! Habe nicht gedacht dass es an den Newlines liegt.
Bei Linefeed bricht die Shell den Parameter von sed in mehrere Teile (falsch! Die Shell bricht das nicht. sed bricht das.). Bei \n nicht. Das wird dann erst von sed zum Linefeed gemacht.
Knogle hat geschrieben: ↑ zum Beitrag ↑
15.12.2018 22:19:34
Gibt es einen guten Weg die zu escapen?
Du könntest vorher in den Variablen die Linefeed durch etwas anderes ersetzen, und das nachher wieder rückgängig machen.

Code: Alles auswählen

$ anton=etwas$'\n'mit$'\n'Linefeed
$ bodo=$(echo -n "$anton"|tr '\n' 'X')
$ echo "kleine Maus im großen Haus"|sed "s/aus/$bodo/g"|sed "s/X/\n/g"
kleine Metwas
mit
Linefeed im großen Hetwas
mit
Linefeed
Ein anderer Weg wäre, IFS zu verbiegen, so dass der Parameter bei Linefeed nicht mehr gebrochen wird.
Wird nicht gehen. Es ist ja nicht die Shell. Man müsste sed erkären, dass die Linefeed im als Parameter übergebenen Script nicht Befehle beenden.
Zuletzt geändert von Lohengrin am 16.12.2018 11:57:13, insgesamt 3-mal geändert.
Harry, hol schon mal das Rasiermesser!

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

Re: Richtige Nutzung von sed

Beitrag von RobertDebiannutzer » 16.12.2018 09:39:56

Lohengrin hat geschrieben: ↑ zum Beitrag ↑
16.12.2018 07:17:06
Bei Linefeed bricht die Shell den Parameter von sed in mehrere Teile. Bei \n nicht.
?
Beispiel:

Code: Alles auswählen

user@hostname:~$ echo -e "hallo\nhallo" > huhu
user@hostname:~$ cat huhu
hallo
hallo
user@hostname:~$ echo -e "Zeile1\nZeile2" > file
user@hostname:~$ var=$(cat file)
user@hostname:~$ sed -i "s/hallo/$var/" huhu
sed: -e expression #1, char 14: unterminated `s' command
user@hostname:~$ cat huhu
hallo
hallo
user@hostname:~$ var=$(cat file | tr -d '\r')
user@hostname:~$ sed -i "s/hallo/$var/" huhu
sed: -e expression #1, char 14: unterminated `s' command
user@hostname:~$ cat huhu
hallo
hallo
user@hostname:~$ var=$(cat file | tr -d '\n')
user@hostname:~$ sed -i "s/hallo/$var/" huhu
user@hostname:~$ cat huhu
Zeile1Zeile2
Zeile1Zeile2
user@hostname:~$ echo -e "hallo\nhallo" > huhu
user@hostname:~$ echo -e "Zeile1\rZeile2" > file
user@hostname:~$ var=$(cat file)
user@hostname:~$ sed -i "s/hallo/$var/" huhu
user@hostname:~$ cat huhu
Zeile2
Zeile2
user@hostname:~$ echo -e "hallo\nhallo" > huhu
user@hostname:~$ var=$(cat file | tr -d '\r')
user@hostname:~$ sed -i "s/hallo/$var/" huhu
user@hostname:~$ cat huhu
Zeile1Zeile2
Zeile1Zeile2
Newline = '\n'
Linefeed = '\r'
oder?

"tr" hatte ich gestern ganz vergessen. Klar, das kann man nehmen. Wenn aber SERVER1 und 2 mehrere Zeilen enthalten sollen, werden die dann halt als eine Zeile eingefügt. Übrigens: https://de.wikipedia.org/wiki/Zeilenumb ... enumbruchs

Knogle
Beiträge: 466
Registriert: 06.05.2016 19:29:00
Lizenz eigener Beiträge: MIT Lizenz

Re: Richtige Nutzung von sed

Beitrag von Knogle » 16.12.2018 10:43:42

Mit tr klappt das zufriedenstellend, jedoch scheint es so, als wuerde das Script versuchen das irgendwie als Befehl auszugeben, und nicht einfach als String einzusetzen.

./test.sh: Zeile 1: /etc/init.d/minecraft_universal start ftb_continuum: Datei oder Verzeichnis nicht gefunden


Hier habe ich ein kleines Testscript

Code: Alles auswählen

SERVER1=$("/etc/init.d/minecraft_universal start ftb_continuum" | tr -d '\r')

echo $SERVER1

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

Re: Richtige Nutzung von sed

Beitrag von RobertDebiannutzer » 16.12.2018 10:50:40

Knogle hat geschrieben: ↑ zum Beitrag ↑
16.12.2018 10:43:42

Code: Alles auswählen

SERVER1=$("/etc/init.d/minecraft_universal start ftb_continuum" | tr -d '\r')

echo $SERVER1
Klar funktioniert das nicht, denn aufgrund der Anführungszeichen sagst Du der Shell, dass sie doch bitte die "Datei" "/etc/init.d/minecraft_universal start ftb_continuum" ausführen soll. Ohne Anführungszeichen würde es funktionieren, denn so wie ich es verstehe, willst Du den output des gestarteten init-Scripts.

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

Re: Richtige Nutzung von sed

Beitrag von Lohengrin » 16.12.2018 11:03:03

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
16.12.2018 09:39:56
Newline = '\n'
Linefeed = '\r'
oder?
Linefeed ist hex 0a, wird oft als LF angzeigt, manchmal als \n maskiert oder eben \x0a (hex), \012 (oct).
Carriage Return ist hex 0d, wird oft als CR angehzeigt, manchmal als \r maskiert oder eben als \x0d (hex) oder \015 (oct).

Code: Alles auswählen

user@hostname:~$ echo -e "hallo\nhallo" > huhu
Hier bricht nicht die Shell, sondern echo. Das Ding hat zwei Parameter $1 ist -e und $2 ist hallo\nhallo (12 Bytes).

Code: Alles auswählen

user@hostname:~$ echo -e "Zeile1\nZeile2" > file
user@hostname:~$ var=$(cat file)
Bei Variablenzuweisung bricht die Shell nicht. Da geht alles in die Variable.
Bei echo $(cat file) wird gebrochen.

Code: Alles auswählen

user@hostname:~$ sed -i "s/hallo/$var/" huhu
sed: -e expression #1, char 14: unterminated `s' command
Hier wird gebrochen. Aber die Shell ist es nicht. Das hat drei Parameter. Irgendwas in sed bricht das Ding, wenn ein LF drin ist.
Ich vermute, dass sed pro Zeile einen Befehl sieht. Wenn LF drin sind, sind das mehrere Zeilen, und bei der nullten Zeile fehlt das Ende vom s-Befehl.

Code: Alles auswählen

user@hostname:~$ var=$(cat file | tr -d '\r')
Das tr tut nichts. In file ist kein CR drin.

Code: Alles auswählen

user@hostname:~$ var=$(cat file | tr -d '\n')
Jetzt ist das LF weg.

Code: Alles auswählen

user@hostname:~$ sed -i "s/hallo/$var/" huhu
user@hostname:~$ cat huhu
Zeile1Zeile2
Zeile1Zeile2
huhu hat zwei Zeilen. In jeder Zeile wurde ersetzt.

Code: Alles auswählen

user@hostname:~$ echo -e "hallo\nhallo" > huhu
user@hostname:~$ echo -e "Zeile1\rZeile2" > file
user@hostname:~$ var=$(cat file)
user@hostname:~$ sed -i "s/hallo/$var/" huhu
Das Ding hat drei Parameter. $1 -i $2 s/hallo/Zeile1␍Zeile2/ (Das ␍ ist U+240D. Es gibt für so etwas extra ein Zeichen, um CR grafisch darzustellen. Sowas kann man mit Strg+Shift+u 240d Enter eingeben) $3 huhu.

Code: Alles auswählen

user@hostname:~$ cat huhu
Zeile2
Zeile2
Schick das mal durch hd!

Code: Alles auswählen

cat huhu |hd
00000000  5a 65 69 6c 65 31 0d 5a  65 69 6c 65 32 0a 5a 65  |Zeile1.Zeile2.Ze|
00000010  69 6c 65 31 0d 5a 65 69  6c 65 32 0a              |ile1.Zeile2.|
0000001c
Wagenrücklauf macht genau das, was der Name besagt.
Zuletzt geändert von Lohengrin am 16.12.2018 12:42:06, insgesamt 3-mal geändert.
Harry, hol schon mal das Rasiermesser!

Knogle
Beiträge: 466
Registriert: 06.05.2016 19:29:00
Lizenz eigener Beiträge: MIT Lizenz

Re: Richtige Nutzung von sed

Beitrag von Knogle » 16.12.2018 11:05:46

Vielen dank! Nun klappt das prima mit dem tr, ich danke dir sehr!

Ich musste jedoch den Ausdruck

Code: Alles auswählen

tr -d '\r')
Durch

Code: Alles auswählen

tr -d '\n')
ersetzen.

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

Re: Richtige Nutzung von sed

Beitrag von RobertDebiannutzer » 16.12.2018 11:41:06

Knogle hat geschrieben: ↑ zum Beitrag ↑
16.12.2018 11:05:46
Ich musste jedoch den Ausdruck

Code: Alles auswählen

tr -d '\r')
Durch

Code: Alles auswählen

tr -d '\n')
ersetzen.
:D

@Lohengrin: Ich glaube, wir haben aneinander vorbeigeredet...

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

Re: Richtige Nutzung von sed

Beitrag von Lohengrin » 16.12.2018 11:49:35

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
16.12.2018 11:41:06
@Lohengrin: Ich glaube, wir haben aneinander vorbeigeredet...
Gut so! Ich bin hier ja auch ins Schleudern gekommen, habe wegen dir herumgespielt und weiß jetzt mehr als vorher.
Harry, hol schon mal das Rasiermesser!

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

Re: Richtige Nutzung von sed

Beitrag von Lohengrin » 16.12.2018 12:35:07

CR ist eine gute Idee. Das wird bei deinem Output nicht vorkommen. Ersetze also mit tr LF durch CR, und mache dann mit sed aus CR \n. Das kannst du dann als Variable an sed geben, was aus den \n dann wieder LF macht.

Code: Alles auswählen

$ anton=etwas$'\n'mit$'\n'Linefeed
$ bodo=$(echo -n "$anton"|tr '\n' '\r'|sed 's/\r/\\n/g')
$ echo "kleine Maus im großen Haus"|sed "s/aus/$bodo/g"
kleine Metwas
mit
Linefeed im großen Hetwas
mit
Linefeed
Harry, hol schon mal das Rasiermesser!

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

Re: Richtige Nutzung von sed

Beitrag von RobertDebiannutzer » 16.12.2018 13:15:57

:THX: Haben alle was gelernt.

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

Re: Richtige Nutzung von sed

Beitrag von Lohengrin » 16.12.2018 16:00:58

Einen hab ich noch. Hat sich nämlich beim Herumspielen ergeben.

Code: Alles auswählen

$ echo $BASH_VERSION
4.4.12(1)-release
$ echo $'dum\ndidum'
dum
didum
$ echo "$'dum\ndidum'"
$'dum\ndidum'
Was ist da los? Warum wird das in " nicht aufgelöst?
Harry, hol schon mal das Rasiermesser!

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

Re: Richtige Nutzung von sed

Beitrag von RobertDebiannutzer » 16.12.2018 17:33:27

Ein schwieriger Fall, denn eigentlich:
Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of $, `, \, and,[…]
Aber ich denke, es liegt an Folgendem:
Enclosing characters in single quotes preserves the literal value of each character within the quotes.
Damit wird "$" nur noch als "literal $" gesehen und nicht mehr als
Words of the form $'string' are treated specially.
Alle Zitate aus "man bash", Kapitel "QUOTING" - gleiche Version wie die von @Lohengrin.

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

Re: Richtige Nutzung von sed

Beitrag von Lohengrin » 16.12.2018 19:43:21

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
16.12.2018 17:33:27
Words of the form $'string' are treated specially.
Words.
Kann es sein, dass das nur geschieht, wenn das etwas mit Word Splitting zu tun hat?
The shell scans the results of parameter expansion, command substitution, and arithmetic expansion that did not occur within double quotes for word splitting.
Vllt ist das, was zwischen " ist, per Definition kein Word.
Harry, hol schon mal das Rasiermesser!

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

Re: Richtige Nutzung von sed

Beitrag von Lohengrin » 20.12.2018 02:28:58

Ich habe gerade trs gefunden. Das kannte ich noch gar nicht.
trs ist wie tr, nur nicht mit Bytes sondern mit Byteketten. trs kümmert sich nicht um LF, arbeitet nicht zeilenweise wie sed, sondern byteweise. LF ist da ein Byte wie jedes andere auch, und kann direkt durch \n ersetzt werden.

Code: Alles auswählen

$ anton=etwas$'\n'mit$'\n'Linefeed
$ bodo=$(echo -n "$anton" | trs '\n \\n')
$ echo "kleine Maus im großen Haus"|sed "s/aus/$bodo/g"
kleine Metwas
mit
Linefeed im großen Hetwas
mit
Linefeed
Harry, hol schon mal das Rasiermesser!

Antworten