[Tcl / Shell] Ändern einer Datei per vi - Änderungsdatum einer Datei erfassen

L

lePasteur

Jungspund
Hallo liebe Leute,

ich habe zwei Probleme, die ich bisher nicht lösen kann, ich hoffe, ihr könnt mir hier weiterhelfen.

Mein erstes Problem:

Ich schreibe gerade ein tcl-Skript, in dem eine Datei verändert werden soll.
Das heisst, ich versuche über den vi diese Datei zu öffnen, eine Zeile zu löschen und zu beenden. Also rufe ich folgenden Befehl im Skript auf:
Code:
exec vi "dateiname" << EOF
/sucheWort
D
ZZ
EOF

Dies funktioniert aber so nicht, es wird eine sehr lange Fehlermeldung angezeigt, u.a. steht dort drin "Found a swap file by the name "~/dateiname.swp" und "Swap file already exists".

Wenn ich iesen Code in meiner shell eingebe (ich benutze SuSE 9.x) kommt die Meldung: "Vim: Warning: Input is not from a terminal" und in der nöchsten Zeile steht in der Eingabe "0;115;0c"

Mein Ziel ist es, im Tcl Skript eine Zeile in einer Textdatei zu suchen, löschen und nachträglich zu ersetzen (hab ich oben bewusst noch nicht gemacht, da ich es bisher alternativ mit cat gelöst habe, was aber auch nicht besonders nützlich ist, da der neue Text an die Stelle des alten sollte).
Wisst ihr, wie das geht? Ich arbeite noch nicht lange mit UNIX, deshalb weiss ich auch nicht, was ihr noch für Angaben braucht.



Mein zweites Problem:

In jenem Tcl Skript soll ich das letzte Änderungsdatum einer bestimmten Datei finden. Habe bisher mit "find -mtime datei" das versucht, aber bei zwei gleichen Dateien, die am gleichen Datum geändert wurden, kommen verschiedene Ergebenisse.
Gibt es einen Tcl oder shell Befehl, mit dem ich direkt das Datum als String bekomme, um zu schauen, welche Datei älter ist?

Ich hoffe, ihr versteht mein Problem und könnt mir helfen.
 
Zuletzt bearbeitet:
Hi,

ad 1) probiers mal an Stelle von "vi" mit "sed" und einem Konstrukt wie
Code:
sed -e 's/sucheWort.*/ersetzeRestvonZeile/' dateiname >dateiname.$$
mv dateiname.$$ dateiname
Gibt zig andere Möglichkeiten (ed, inline edit mit Perl, ...), aber "vi" zu skripten, ist meist nicht die einfachste Lösung ;-)

ad 2) schon mal das file-Kommando in Tcl, speziell die Operation mtime angeschaut? Sollte doch genau das gewünschte liefern ...

Gruesse,
A.
 
1) werd ich gleich mal schauen ob das klappt.

2) Ja, das habe ich bisher benutzt, nur ich bekomme unterschiedliche Strings bei zwei verschiedenen Dateien, die aber gleichzeitig erstellt wurden, das macht mich stutzig.
Habe gerade "test -nt gefunden", werde das auch gleich mal probieren, wollte nur schnell antworten.

Edit:

zu 2)
also hab es mal im Skript beispielsweise versucht mit
Code:
set t [exec test datei1 -nt datei2]
puts $t
was aber die Meldung
"child process exited abnormally"
brachte.


zu 1)
Da ist mir die Syntax nicht ganz klar. Welche Anführungszeichen muss ich benutzen? bei ' kommt die meldung, dass der command name '' unbekannt ist. Bei " " kommt "Error:sed: -e expression #1, char 26: unknown option to 's' "
 
Zuletzt bearbeitet:
Hi,

ad 1) bei mir läuft das mit single quotes wie im Beispiel oben; direkt nochmal mit copy & paste getestet. Evtl. kannst du ja mal das genaue Kommando hier reinkopieren, das bei dir zu der Fehlermeldung geführt hat?

ad 2) noch ein bisschen mit Tcl rumgespielt (ist lange her :) ) ... bei mir funktioniert das mit 'file mtime ...' problemlos:
Code:
#!/usr/bin/tclsh


set t1 [file mtime TEST1]
puts "TEST1: $t1"

set t2 [file mtime TEST2]
puts "TEST2: $t2"

if { $t1 < $t2 } {
        puts "\nTEST2 is NEWER"
} else {
        puts "\nTEST1 is NEWER"
}

Dein "test ... -nt" liefert dir nicht den Namen (oder das Modifikationsdatum) der neueren Datei zurück, sondern einen Exit-Status 0, wenn die zuerst genannte neuer ist als die zweite, sonst 1. "child process terminated abnormally" heisst also m.E. nur, dass deine zweite Datei die neuere ist.

Gruss, A.
 
Also es kommt mit copy und paste folgende Fehlerneldung:

Code:
sed: -e expression #1, char 1: unknown command: `''
sed: -e expression #1, char 1: unknown command: `''
    while executing
"exec sed -e 's/$nkey.*/$nkey [.cfgwin.$path get]/' $CFG(PATHCFG) >$CFG(PATHCFG).$$"
    (procedure "sav" line 23)
    invoked from within
"sav INST_DICT destentry  "
    invoked from within
".cfgwin.destsave invoke"
    ("uplevel" body line 1)
    invoked from within
"uplevel #0 [list $w invoke]"
    (procedure "tk::ButtonUp" line 22)
    invoked from within
"tk::ButtonUp .cfgwin.destsave"
    (command bound to event)

Muss ein exec davor oder nicht?

zu 2) Bei anderen Dateien klappt es, jedenfalls die, die ich getestet habe. Nur da war jetzt ein kleiner Fehler drinne, der mich stutzig macht.
 
Braucht auf jeden Fall ein exec davor; und innerhalb des tcl-Skripts musst du doch double quotes verwenden (ich hatte das nur auf der Kommandozeile getestet).

A.
 
Wenn ich das sed .... $$ in """ setze, kommt die Fehlermeldung: Couldn't execute "sed -e ...." no such file or directory.

In der Shell funktionier das Kommando einwandfrei, aber im Tclskript kommt, wenn ich das ganze hinter exec schreibe, der Fehler:

Error:sed: -e expression #1, char 26: unknown option to 's'.
 
Zuletzt bearbeitet:
... mal nur um den "Substitute"-Befehl:
Code:
exec sed -e "s/$nkey.*/$nkey [.cfgwin.$path get]/" ...
 
Bei " " kommt der gleiche Fehler, und bei ' ' kommt der Fehler mit ' ' statt 's' :(
Und ganz ohne Leerzeichen klappt auch nich.
 
Zuletzt bearbeitet:
Also, wenn ich das in 'ne tclsh paste, bekomme ich nur eine Meldung wie
Code:
% exec sed -e "s/$nkey.*/$nkey [.cfgwin.$path get]/" <DATA
can't read "nkey": no such variable
%
und das Bsp. von vorhin mit Dummy-Daten und double-quotes ist bei mir so gelaufen.

Könnte mir noch vorstellen, dass die "square brackets" innerhalb des substitute-Befehls noch Probleme machen, weil die ja auch noch von Tcl ausgewertet werden; würde da aber eigentlich 'ne andere Fehlermeldung erwarten ...

Kannst du mal ein paar Zeilen Code rüberschieben, die möglichst standalone lauffähig sind, um das Problem zu reproduzieren? Oder hat sich die Geschichte inzwischen sowieso erledigt?
 
Also, der Stand der Dinge:

Ich führe den Befehl mit -i statt -e auf.
Habe verschiedene Möglichkeiten probiert, und zwar:

- square brackets herausgenommen, diesen Wert vorher in eine Variable gespeichert und diese eingesetzt

- einmal mit direktem überschreiben, einmal mit Zwischenspeichern und mv (wobei es hierbei auch einen Fehler gab:

mein Kommando sah so aus:

exec sed -i "s/$key.*/$key $entry/" $CFG(CFG_FILE) > $CFG(CFG_FILE).x
exec mv $CFG(CFG_FILE).x $CFG(CFG_FILE)

Am Ende konnte ich nur eine leere Cfg-Datei vorfinden mit dem alten Dateinamen.

- per externes Shell-Skript

Ich hab ein Standalone-Skript geschrieben, das klappt wunderbar, nur im großen Programm funktioniert das nicht, es kommt immer wieder derselbe Fehler.


Vielleicht allgemein was zum Programm, da ja die Standalone-Version mit Variablen funktioniert:

Es wird beim Programmstart eine Konfigurationsdatei geladen und alle Attribute in verschiedene Variablen gesteckt. Der Benutzer soll durch ein Config-Fenster die Möglichkeit haben, die Configuration für eine Sitzung (d.h. bis das Prog geschlossen wird) oder im CFG-File zu speichern. Und gerade dieses Speichern klappt nicht, das Setzen der Werte schon.

Der Ablauf ist folgender, wenn der Save-Button geklickt wird:
Code:
setzte CFG(CFG_FILE) auf den eingegebenen Pfad
Lies die Datei ein und setze alle Attribute des neuen Files (eigene Proc)
set chan [open $CFG(CFG_FILE)]
set lineNumber 0
while {[gets $chan line]>=0} {
 scan $line %s nkey
if { [string equal $nkey $key]==1 } { # key steht hierbei für ein angegebens Attribut, mit dem die Proc aufgerufen wird
set entry [.cfgwin.$path get] # path ist das zweite Attribut
exec sed -i "s/$key.*/$key $entry/" $CFG(CFG_FILE)
alternativ auch mit der .x-Variante

Zu bemerken ist aber, dass ich vorher nicht die CFG-Werte neu eingelesen habe und das CFG-File auch nicht neu gesetzt habe. So hat es funktioniert, solange ich eine andere Datei angegeben habe, als die momentane CFG-Datei. Hier könnte eventuell der Knackpunkt sein, oder?

Achja, die Rechte sind 755 bei allen Dateien, die ich getestet habe, einzulesen.

Achja, das Standalone-Skript:
Code:
entry .test 
button .b -text "Teste" -command { 
set npgm [.test get]
set test "s/INST_DICT.*/INST_DICT $npgm/"
exec sed -i $test t.txt

}

pack .test .b -side left
Klappt auch mit Variablen statt "INST_DICT".
 
Hi,

sieht mir doch danach aus, als ob das Problem darin liegt, dass du über zwei Kanäle gleichzeitig deine CFG-Datei zu bearbeiten versuchst: auf der einen Seite liest du über den File-Deskriptor chan das Ding zeilenweise ein; sobald du ein Attribut findest, rufst du sed auf, und der verändert dann die Datei, die du gerade liest ... sportlich ... :)

Mit der -i-Option bei sed (inline editing; gibts halt leider nicht auf allen Systemen) brauchst du das Konstrukt mit der temp-Datei natürlich nicht. Sonst passiert genau das, was du gesehen hast: sed erzeugt wahrscheinlich da intern schon eine solche temporäre Datei, schreibt seine Ergebnisse da rein, und überschrebit dann die alte mit der neuen. Wenn du jetzt noch den Output von sed benutzt (ist in dem Fall ja leer) und über die Originaldatei schiebst, bekommst du ein leeres Config-File.

Wenn du sowieso die Datei schon zeilenweise liest, was spricht dagegen, einfach Zeile für Zeile in eine temp. Datei mitzuschreiben, dabei die Attribute gleich zu aktualisieren, und dann die Files entsprechend umzuubenennen? Spart das ganze sed-Gehampel ...

Grüsse,
A.
 
Zuletzt bearbeitet:
Dass ich da nicht früher drauf gekommen bin! Habs jetzt gelöst, wie du es gesagt hast, ist ja viel einfacher. Naja, wenn man sich einmal was in den Kopf gesetzt hat, entfallen schnell die anderen Möglichkeiten im Kopf...
Jedenfalls funktioniert es jetzt.

Vielen Dank!
Grüße,
Jan
 
Ist zwar ein Doppelpost, aber anders sieht man es ja sonst nicht, oder?

Gibt es einen Befehl oder Methode in Unix, die den absoluten Pfad eines momentan aufgerufenen Skriptes ausgibt?

Beispiel:

Ich befinde mich im Ordner "/root/ordner1/unterordner1", rufe von da aus das Skript "bsp.sh" im Ordner /root/Ordner1/unterordner2" auf.
In diesem Skript gibt es eine Variable, die den Pfad des Skriptes "bsp.sh" zurückgibt. Je nachdem, wo also dieses Skript liegt, ändert sich auch der Variablenwert.

Hat da wer eine Möglichkeit?
 

Ähnliche Themen

Keine grafische Oberfläche (Debian Installation)

.cfg Datei Analysieren und Zeilen Stellenweise abändern

Prblem mit zeilenweises auslesen von Datei und schreiben nach mysql

Zeichenkette per Skript an shell übergeben

CSV Datei mit sed manipulieren/optimieren/ergänzen

Zurück
Oben