PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : awk - Dinge in einer Datei ersetzen



ThorstenS
30-04-2008, 20:28
Hi Leute,

ich möchte unter Linux in der Datei /etc/fstab den String /dev/hda oder /dev/hde durch /dev/cdrom ersetzen. Das funktioniert bereits:

$ cat /etc/fstab
# /etc/fstab: static file system information.
#
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
/dev/hda1 / ext3 errors=remount-ro 0 1
/dev/hda3 /home ext3 defaults 0 0
/dev/hda2 none swap sw 0 0
/dev/hde /media/cdrom0 udf,iso9660 user,noauto 0 0

$ awk '/cdrom/ { $3 = "cdrom\t" ; print } !/cdrom/ { print} ' FS='/' OFS='/' /etc/fstab
# /etc/fstab: static file system information.
#
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
/dev/hda1 / ext3 errors=remount-ro 0 1
/dev/hda3 /home ext3 defaults 0 0
/dev/hda2 none swap sw 0 0
/dev/cdrom /media/cdrom0 udf,iso9660 user,noauto 0 0

Nur wie kann die den Output direkt wieder in die fstab schreiben?
Sowas wie < fstab > fstab leert mir die Datei. Auch ein echo fstab | awk ... > fstab bringt leider nicht das gewünschte Ergebnis.

Ich suche also sowas wie das --infile von sed. Den Umweg über eine 2. Datei möchte ich gerne vermeiden...

ContainerDriver
30-04-2008, 21:23
Blöde Frage: warum machst du es nicht einfach mit sed?

ThorstenS
01-05-2008, 09:44
1.) weil ich awk mag und mich nicht vor etwas schwieriger anmutenden Problemen von dessen Einsatz abhalten lassen möchte
2.) weil ich keine sed Lösung habe

Ich habe oben /dev/hda oder /dev/hde geschrieben. Auf anderer Hardware kann das auch hdb - hdg sein. Die awk Lösung ist dafür flexibel genug ausgelegt.

EDIT: Die sed Lösung:
sed -i -re '/cdrom0/s#(/dev/)\w+#\1cdrom#' /etc/fstab


Trotzdem suche ich noch nach einer Lösung, um mit awk eine Datei diretk verändern zu können.

undefined
01-05-2008, 15:29
und - wo liegt das problem ?
mal davon abgehen das ich bei so einem eingriff 100% mit backups arbeiten würde ;)

cat /etc/fstab | awk ........ > /etc/fstab

ContainerDriver
01-05-2008, 15:44
und - wo liegt das problem ?
mal davon abgehen das ich bei so einem eingriff 100% mit backups arbeiten würde ;)

cat /etc/fstab | awk ........ > /etc/fstab

Da bekommst du aber nur eine leere Datei zurück.



[florian@leuchtturm1 tmp]$ cat lines
Hallo
Welt
Zeile1
Zeile2
Zeile3
Zeile4
Zeile5
[florian@leuchtturm1 tmp]$ cat lines|awk '{print $0}'>lines
[florian@leuchtturm1 tmp]$ cat lines
[florian@leuchtturm1 tmp]$


Man kann aber die Dateiumleitung in das awk-Programm einbauen (oder hast du das gemeint undefined?), dann funktioniert das ganze:


[florian@leuchtturm1 tmp]$ cat test_file
# /etc/fstab: static file system information.
#
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
/dev/hda1 / ext3 errors=remount-ro 0 1
/dev/hda3 /home ext3 defaults 0 0
/dev/hda2 none swap sw 0 0
/dev/hde /media/cdrom0 udf,iso9660 user,noauto 0 0
[florian@leuchtturm1 tmp]$ awk '/cdrom/ { $3 = "cdrom\t" ; print >"test_file" } !/cdrom/ { print >"test_file"} ' FS='/' OFS='/' test_file
[florian@leuchtturm1 tmp]$ cat test_file
# /etc/fstab: static file system information.
#
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
/dev/hda1 / ext3 errors=remount-ro 0 1
/dev/hda3 /home ext3 defaults 0 0
/dev/hda2 none swap sw 0 0
/dev/cdrom /media/cdrom0 udf,iso9660 user,noauto 0 0


Gruß, Florian

undefined
01-05-2008, 16:30
Dann soll er halt ... 1>&2> schreiben ;-)

BLUESCREEN3D
01-05-2008, 22:58
Im Zweifelsfall gibt es ja immernoch diesen Shell-Trick, mit dem man den Dateinamen weiterverwenden kann (genau genommen wird die Datei geöffnet, gelöscht und neu erstellt):

(rm datei && awk '{print $0}' > datei) < datei

jan61
02-05-2008, 15:31
Moin,


Dann soll er halt ... 1>&2> schreiben ;-)

Was soll das bringen? Was willst Du mit STDERR (&2) da?

Das grundsätzliche Problem solcher Inplace-Ersetzungen ist, dass man nie sicher sein kann, wieviel vom Inhalt einer zu lesenden Datei bereits im Speicher ist, bevor die Schreiboperationen tatsächlich auf der Platte landen und ob der Lese-Filedescriptor schon zu ist, wenn geschrieben wird. Es ist also bei allen vorgeschlagenen Lösungen (außer sed -i) reine Glückssache, ob die Datei anschließend leer, verstümmelt oder vollständig ist.

Da spielen Timings zwischen Lesen, Pipen, Schreiben eine Rolle, programminterne Abläufe (z. B. in welcher Reihenfolge und wann werden Filedescriptoren geöffnet und wieder geschlossen), Größe von R/W-Puffern usw. - das kann man von außen überhaupt nicht steuern, weil da viele Faktoren reinspielen: Hardware, Betriebssystem, Anwendung, Rechnerauslastung, Dateigröße, ...

Ich würde also die Finger lassen von allen Versuchen, in eine zum Lesen geöffnete Datei gleichzeitig wieder reinzuschreiben (es sei denn, ich mache das in einem Programm gezielt über seek und tell).

Eine Variante, das "in Place" mit awk zu regeln (wobei ich keine Ahnung habe, warum Du Dich so gegen eine temp. Datei sträubst) ginge so (ungetestet):

awk '/cdrom/ { # Aendern
$3 = "cdrom\t" ;
# in Array ablegen
arr[NR] = $0;
}
!/cdrom/ { # in Array ablegen
arr[NR] = $0;
}
END { # jetzt alles ausgeben, hier ist das Einlesen beendet
for (i in arr) print arr[i] >"/etc/fstab"; } ' FS='/' OFS='/' /etc/fstab
Hier halte ich also den Dateiinhalt im Programm im Speicher und schreibe ihn erst dann weg, wenn ich alles gelesen habe. Geht natürlich nur bei Dateien mit überschauberer Größe.

Ich persönlich bevorzuge für solche Sachen allerdings den Umweg über eine temp. Datei - schon allein deshalb, weil ich dann sicherstellen kann, dass nur dann die Originaldatei ersetzt wird, wenn das Bearbeiten geklappt hat:
TMP_FSTAB=`mktemp` || exit 1
awk ' ... ' /etc/fstab >$TMP_FSTAB && mv $TMP_FSTAB /etc/fstabJan

ThorstenS
02-05-2008, 20:24
Danke für eure Anworten und das Mitdenken, speziell dir Jan.
Der Trick das im END Bereich unterzubringen ist genial wie auch logisch - gefällt mir gut.