shell: bis START lassen dann ersetzen ab END wieder lassen

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
lemak
Beiträge: 1213
Registriert: 09.11.2007 13:25:57
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

shell: bis START lassen dann ersetzen ab END wieder lassen

Beitrag von lemak » 01.04.2012 18:51:54

Hallo,

ich habe eine Datei wie folgt:

Code: Alles auswählen

foo=bar
#START
bar=foo
#END
bla=blub
Nun soll der Block #START bis #END vom einem Skript ersetzt werden.

//Edit: Lösung:

Code: Alles auswählen

#!/bin/sh
# reads options (var = val) line-wise from STDIN and writes them to $1
# by replacing the START-END region
set -e
if [ ! -e "$1" ]; then
	printf "%s\n%s\n" "#START" "#END" >"$1"
fi
# has the file markers and the right way round?
awk '
/^#START$/ {ls=NR; s++}
/^#END$/   {le=NR; e++}
END {
	if (s!=1||e!=1||le < ls) {
		printf("%s: missing, half-open or more than one START-END region.\n", "'$1'");
		exit 112;
	}
}' "$1" >&2
# replace START-END region
sed -i '/^#START$/,/^#END$/c \
#START\
# Do not edit within this region\! Make youre changes after the END mark.\
'"$(while read option; do echo "$option\\"; done)"'
#END' "$1"
Zuletzt geändert von lemak am 21.02.2014 19:12:50, insgesamt 25-mal geändert.

newdeb
Beiträge: 134
Registriert: 03.02.2011 11:11:21
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Frankfurt

Re: shell: bis START lassen dann ersetzen ab END wieder lass

Beitrag von newdeb » 01.04.2012 21:24:18

mit dem sed c(hange)-Kommando?

Code: Alles auswählen

CHANGE='neue Zeile 1\
neue Zeile 2'

sed '/#START/,/#END/c \
#START\
'"$CHANGE"'\
#END' $filepath 

lemak
Beiträge: 1213
Registriert: 09.11.2007 13:25:57
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: shell: bis START lassen dann ersetzen ab END wieder lass

Beitrag von lemak » 02.04.2012 09:54:09

Das gefällt mir schon mal besser - Vielen Dank.

Wenn jetzt noch jemandem was einfällt wie man elegant testen könnte, das #START auch vor #END steht, wäre das super!

Benutzeravatar
Livingston
Beiträge: 1816
Registriert: 04.02.2007 22:52:25
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: 127.0.0.1

Re: shell: bis START lassen dann ersetzen ab END wieder lass

Beitrag von Livingston » 02.04.2012 13:22:10

Hier mal ein ungetester Ansatz

Code: Alles auswählen

# genau ein START- und END-Token?
if [ $(grep -c "#START" DATEI ) -ne 1 ] || [ $(grep -c "#END" DATEI) -ne 1 ]; then
    exit 1
    # oder andere Fehlerbehandlung
fi

# START vor END?
STARTZEILE=$(grep -n "#START" DATEI | cut -d":" -f1)
ENDZEILE=$(grep -n "#END" DATEI | cut -d":" -f1)

if [ ${STARZEILE} -ge ${ENDZEILE} ]; then
    exit 1
    # oder eine andere Fehlerbehandlung
fi

# Weiter wie bereits gepostet

newdeb
Beiträge: 134
Registriert: 03.02.2011 11:11:21
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Frankfurt

Re: shell: bis START lassen dann ersetzen ab END wieder lass

Beitrag von newdeb » 02.04.2012 15:04:37

Testen mit awk:

Code: Alles auswählen

awk '
/#START/{zs=NR;s++}
/#END/  {ze=(e)?ze:NR;e++}
END     {if (s!=1||e!=1||ze<=zs) exit 1}
' $filepath 
# hier Returncode ($?) testen

lemak
Beiträge: 1213
Registriert: 09.11.2007 13:25:57
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: shell: bis START lassen dann ersetzen ab END wieder lass

Beitrag von lemak » 02.04.2012 20:46:09

Cool - So macht awk lernen Spaß :-)

Mich würde noch interessieren:
Warum sollte ich

Code: Alles auswählen

awk -v text=text 'BEGIN{printf("%s\n", text)}';
anstatt von

Code: Alles auswählen

awk 'BEGIN{printf("%s\n", "'text'")}';
nutzen?

Letzteres ist doch nur hart-kodiert und funktioniert deshalb NICHT in reinen awk-Skripten!? Oder gibt noch einen anderen Grund es so nicht zu tun?

@Livingston: Besser habe ich es auch nicht hinbekommen.

@newdeb: Ich hätte es wohl sicher nicht so gut hinbekommen - Vielen Dank nochmal.
Zuletzt geändert von lemak am 21.02.2014 19:08:03, insgesamt 1-mal geändert.

newdeb
Beiträge: 134
Registriert: 03.02.2011 11:11:21
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Frankfurt

Re: shell: bis START lassen dann ersetzen ab END wieder lass

Beitrag von newdeb » 02.04.2012 23:02:23

up hat geschrieben:Mich würde noch interessieren:
Warum sollte ich

Code: Alles auswählen

awk -v text=text 'BEGIN{printf("%s\n", text)}';
anstatt von

Code: Alles auswählen

awk 'BEGIN{printf("%s\n", "'text'")}';
nutzen?
Wer fordert das denn? :o
In der 2. Variante wird das awk-Skript wegen der inneren Hochkommata unterbrochen, und 'text' steht sozusagen in der Shell-Kommandozeile.
Deutlicher wird das, wenn du eine Shellvariable verwendest, diese wird vor der awk-Ausführung expandiert:

Code: Alles auswählen

text=foo; awk 'BEGIN{printf("%s\n", "'$text'")}'
Man kann das also durchaus so machen wie in Variante 2, ein weiteres Beispiel ist das sed-Kommando in meinem Post.
Die Wertübergabe an die awk-Variable (Variante 1) ist sicher eleganter und leichter lesbar.

Antworten