sonnenblen.de - Das unabhängige Sun User Forum
Software => Programmieren, Kompilieren => Thema gestartet von: signal_15 am 01. April 2009, 11:02:38
-
Hi,
bin auf der suche nach einer einfachen methode um eine zeile text in eine datei oben am anfang rein zu schreiben.
ein
echo "bla blub" >> /irgendwo/datei
schreibt mir den inhalt an das ende der datei. ich moechte aber den bisherigen inhalt der datei um zeile nach unten verschieben und den inhalt oben drauf geben. hat da jemand eine idee?
ct,
-
Hallo,
vielleicht die Zeile in eine Datei schreiben und den umgekehrten Weg gehen?
Also das Ziel-File an das File mit der einen Zeile haengen und am Ende den Dateinamen aender...
Glaub das sollte gehen, oder?
MfG Michael
-
habs nun folgendermasen gemacht:
echo "bla blup" >> $temp1
cat $datei >> $temp1
cat $temp1 > $datei
ein einzeiler waere mir aber trotzdem lieber gewesen. so muss cat zwei mal laufen und auf dauer, wenn die datei groesser wird, wird's immer langsamer.
ct,
-
ein einzeiler waere mir aber trotzdem lieber gewesen. so muss cat zwei mal laufen und auf dauer, wenn die datei groesser wird, wird's immer langsamer.
Geht doch:
echo "bla blup" >> $temp1; cat $datei >> $temp1; cat $temp1 > $datei
Gruss
Dominik
-
@dominik
der war gut.-)
ct,
-
Dem Editör is nix zu schwör ;D
/usr/bin/echo '0a\nbla blub\n.\nw\nq' | ed -s $datei
Rainer
-
@dornroeschen
na also, geht doch. sieht doch schon mal recht vielversprechend (oder heisst es 'viel versprechend') aus. ich glaub nicht, dass ich das script noch heute anpassen werde. aber ich gebe dann bescheid.
ct,
-
Dem Editör is nix zu schwör ;D
/usr/bin/echo '0a\nbla blub\n.\nw\nq' | ed -s $datei
Rainer
Hallo.
Das wird allerdings bei großen Dateien nicht funktionieren.
Das "unten dran-Hängen" ist eine Operation, die jedes Betriebssystem von sich aus unterstützt. Ein direktes "oben dran-Kleben" ist bei den mir bekannten Dateisystemen (FAT, NTFS, UFS, EXT2) wohl unmöglich.
Die Datei muss beim "oben dran-Kleben" also komplett neu geschrieben werden. Dazu gibt es zwei Möglichkeiten:
- Die zwei-Dateien-Lösung
- Die Datei komplett in den RAM lesen und dann schreiben (Lösung mit dem "ed"-Editor)
Da bei großen Dateien aber nicht genügend RAM zur Verfügung steht, ist das ein Problem.
habs nun folgendermasen gemacht:
echo "bla blup" >> $temp1
cat $datei >> $temp1
cat $temp1 > $datei
Mehr Performance würde der folgende Code bringen, da kein zweites Umkopieren notwendig ist:
echo "bla blup" > $temp1
cat $datei >> $temp1
rm $datei
mv $temp1 $datei
(Allerdings gehen dabei UID, GID, Mode, ... von "$datei" verloren)
Martin
-
@Martin
richtig. und ich brauche/habe folgendes:
total 46K
drwxr--r-- 2 root other 512 Apr 1 16:35 .
drwxr-xr-x 14 root other 1.0K Mar 31 14:02 ..
-rw-r--r-- 1 daemon other 7.1K Apr 1 16:50 index.shtml
-rw-r--r-- 1 root other 12K Apr 1 14:22 index.shtml_Backup_2009_04_01
-rw-r--r-- 1 daemon other 6.3K Apr 1 16:50 news-db
-rw-r--r-- 1 root other 1.2K Apr 1 14:37 test.shtml
man koennte das script als 'daemon' laufen lassen. aber dann muesste auch das verzeichnis dieser uid gehoeren, oder zumindest die schreib/lese-rechte geaendern werden. und das soll nicht sein.
ct,
-
Dem Editör is nix zu schwör ;D
/usr/bin/echo '0a\nbla blub\n.\nw\nq' | ed -s $datei
Rainer
Hallo.
Das wird allerdings bei großen Dateien nicht funktionieren.
Völlig richtig. Jede Lösung ist gut/nicht gut bzw geht/geht nicht nur im Rahmen der bekannten/nicht bekannten Randbedingungen. Ich finde den ed als Skripting Tool für Inline-Editing ganz interessant, solange klar ist, dass die Begrenzungen des Tools nicht überschritten werden. Beim Solaris ed sind dies die maximale Zeilenlänge von 512 Zeichen, und die Begrenzung der Zeilen durch die Speichergröße. Wie die Beschränkungen des GNU-ed aussehen, weiss ich jetzt nicht.
Alternativ kann man identisch auch den ex (vi) einsetzen, oder die ex-Variante des vim. Ich glaube nicht, dass vim oder auch nvi eine Beschränkung der Zeilenlänge haben.
Rainer
-
Ja hier sehen wir wieder mal das Problem das Filesysteme vom Programmiertechnischen sich seit fast 30 Jahren nicht verändert haben. Eine Datei als Queue die vorne und hinten anfügen und entfernen unterstützt und das reinschiessen von Löchern (Sparse Files) ist eigentlich so sinnvoll.
Aber egal. Ich würde gerne wissen wozu du das brauchst. Denn ich denke du setzt falsch an. Vorne und hinten sind technisch irgendwie gleich. Wenn es wegen anzeige der Daten ist ändere die Datenanzeige.
-
habs nun folgendermasen gemacht:
echo "bla blup" >> $temp1
cat $datei >> $temp1
cat $temp1 > $datei
ein einzeiler waere mir aber trotzdem lieber gewesen. so muss cat zwei mal laufen und auf dauer, wenn die datei groesser wird, wird's immer langsamer.
Bei der Größenordnung würde ich mir um Performance keine Gedanken machen. Ein paar kB machen auf einem Rechner mit Gigabytes an RAM wirklich kein Problem.
Sollte das wirklich in messbare Regionen kommen, wirst du wahrscheinlich sowieso messen müssen, welche Variante die beste ist.
Was mir sonst noch eingefallen ist:
- cat kommt auch mit mehreren Files als Parameter zurecht
- eine Zeile einfügen geht auch mit sed statt ed
- wenn es mehr als eine Zeile sein soll, können ed und sed auch ein ganzes File einfügen.
- Einige sed Varianten (GNU z.B.) können mit -i auch die Datei in-place bearbeiten
-
$llothar
ich habe ein shell skript als cgi auf einem apachen laufen, welches neue nachrichten aus einem webformular zuerst in eine plain-text datei schreibt und diese dann in eine html seite einfuegt.
#!/bin/sh
# create entry on the news page
umask=022
grep=/usr/bin/grep
awk=/usr/local/bin/awk
cat=/usr/local/bin/cat
temp1=/tmp/tmp.$$
temp2=/tmp/tmp.$$
mdate=`date "+%d %B %Y"`
mtime=`date "+%H:%M"`
newsdb=/var/www/news/news-db
newsindex=/var/www/news/index.shtml
newsheader=/var/www/news/news-header
newsfooter=/var/www/news/news-footer
eval `/usr/local/bin/proccgi.sh $*`
# build the news-db
echo "<tr><td>$mdate</td><td>$mtime</td><td></td><td><b>$FORM_ueberschrift</b></td></tr>" >> $temp1
echo "<tr><td> </td><td> </td><td></td><td>$FORM_nachricht <br><br></td></tr>" >> $temp1
$cat $newsdb >> $temp1
$cat $temp1 > $newsdb
# build the page
/usr/local/bin/cat $newsheader > $newsindex
/usr/local/bin/cat $newsdb >> $newsindex
/usr/local/bin/cat $newsfooter >> $newsindex
# clean up
rm -r $temp1
echo "Content-type: text/html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<body><p>yeah, check the news site</p></body></html>"
exit 0
ct,
Edith sagt: Name falsch geschrieben.
-
$llothar
ich habe ein shell skript als cgi auf einem apachen laufen, welches neue nachrichten aus einem webformular zuerst in eine plain-text datei schreibt und diese dann in eine html seite einfuegt.
So was hab ich mir gedacht. Da du die Datei ja sowieso komplett liest häng es unten dran und mach ein "reverse" und beim dranhängen dann natürlich auch noch ein reverse. Man kann mittels tail -n auch die letzten zeilen ausgeben.
Vorne dran hängen würde ich nichts. Umkopieren ist viel aufwendiger als lesen und umdrehen.
-
@llothar
jetzt habe ich deinen faden verloren. wie meinen?
ct,
-
Was ist denn gegen tac zu sagen. Damit gibst Du den Inhalt rückwärts aus und kannst die neuen Zeilen unten dranhängen....
-
@llothar
jetzt habe ich deinen faden verloren. wie meinen?
Ich bin jetzt nicht der Shell Scripter aber irgendwas wie
cat neue_nachricht.txt | reverse -l >> datei_mit_allen_nachrichten.txt
sowie
tail -n 100 datei_mit_allen_nachrichten.txt | reverse -l
"reverse -l" ist jetzt aber ein selbstgeschriebenes Tool. Hab gerade kein Unix am
laufen um zu sehen wie der Parmaeter wirklich heisst. "reverse -l" nimmt die
Eingabe entgegen und gibt sie umgekehrt wieder aus, mit option "-l" basierend
auf Zeilenbasis.
Mit obigem würdest du in der ersten Zeile halt eine Nachrichten an dein Nachrichten Log anhängen.
Und mit der zweiten Zeile die letzten 100 Zeilen aller Nachrichten ausgeben.
Komplexität ist immer O(n) mit n der Grösse der hinzufügenden Nachricht und der Anzahl der
Zeilen die du im CGI script ausgeben würdest. Selbst wenn deine Datei in der du die
Nachrichten sammelst Gigabyte gross wird ist das also noch extrem performant.
Edit:
Erst jetzt sehe ich das Toktar geantwortet hat.
Statt reverse also "tac" nutzen und fertig.
-
Erst jetzt sehe ich das Toktar geantwortet hat.
Statt reverse also "tac" nutzen und fertig.
oder /usr/bin/tail -r ;D
Rainer
-
Guten Morgen,
ich bin jetzt bei meiner ersten version geblieben. sie funktioniert wie geplant und laeuft auch schnell genug.
# build the news-db
echo "<tr><td>$mdate</td><td>$mtime</td><td></td><td><b>$FORM_ueberschrift</b></td></tr>" >> $temp1
echo "<tr><td> </td><td> </td><td></td><td>$FORM_nachricht <br><br></td></tr>" >> $temp1
$cat $newsdb >> $temp1
$cat $temp1 > $newsdb
# build the page
/usr/local/bin/cat $newsheader > $newsindex
/usr/local/bin/cat $newsdb >> $newsindex
/usr/local/bin/cat $newsfooter >> $newsindex
das ganze mit 'tail -r' oder reverse, haette gar nicht mal so leicht geklappt da die neuen eintraege mehrzeilig sind und bei einem 'tail -r' dann alles durcheinander gewuerfelt worden waere.
ct,
-
Guten Morgen,
ich bin jetzt bei meiner ersten version geblieben. sie funktioniert wie geplant und laeuft auch schnell genug.
Ich bin der festen Überzeugung, dass die meisten vorausschauenden Optimierungen gar nicht nötig sind. ;-)
So ad hoc würden mir noch die folgenden Änderungen einfallen:
# build the news-db
echo "<tr><td>$mdate</td><td>$mtime</td><td></td><td><b>$FORM_ueberschrift</b></td></tr>" > $temp1
echo "<tr><td> </td><td> </td><td></td><td>$FORM_nachricht <br><br></td></tr>" >> $temp1
$cat $newsdb >> $temp1
mv $temp1 $newsdb
# build the page
/usr/local/bin/cat $newsheader $newsdb $newsfooter > $newsindex
- Beim ersten echo solltest du das >> durch ein > ersetzen, um das File garantiert neu anzulegen (falls das nicht weiter oben schon passiert)
- Ein Umbenennen ist schneller als ein Kopieren, das mv kannst du natürlich noch als $mv oder "mv -f" nach Geschmack anpassen.
- Und ein cat mit drei Parametern ist schneller als dreimal cat mit einem File. :-)
-
temp1=/tmp/temp.$$
somit ist das file garantiert angelegt.
/usr/local/bin/cat $newsheader $newsdb $newsfooter > $newsindex
gefaellt mir gut und werde ich so uebernehmen.
ct,
-
temp1=/tmp/temp.$$
somit ist das file garantiert angelegt.
Das ist ja nur der Filename, was passiert, wenn z.B. bei einem lange laufenden System die Pid zum zweiten Mal vergeben wird? Ist zugegebenermassen unwahrscheinlich, aber ich würde dennoch das erste >> in ein > wandeln, damit wird das File entweder neu angelegt oder zumindestens der alte Inhalt gelöscht.
BTW: Wäre auch noch zu überlegen, ob du $temp1 nicht zum Schluß löschst, damit in /tmp nicht zu viel Müll liegen bleibt.
-
am ende des scripts laeuft ein 'rm -r $temp1', somit habe ich das tmp-verzeichnis vor vermuellung verschont und sichergestellt, dass die tmp-datei wieder garantiert leer sein wird.-)
aber ich sehe schon, du willst das erste >> durch ein > unbedingt ersetzt sehen.-) werde ich machen.
ct,
-
das ganze mit 'tail -r' oder reverse, haette gar nicht mal so leicht geklappt da die neuen eintraege mehrzeilig sind und bei einem 'tail -r' dann alles durcheinander gewuerfelt worden waere.
Schau dir noch mal meine Lösung an.
Das war mir schon bewusst.
Deshalb must du ja vor dem Anhängen ein reverse auf die Nachricht machen,
denn reverse + reverse ist wie not + not oder Merkel + Steinmüller, alles ist null und leere Luft.
-
@llothar
ich hab gerade eben 'm meik zugesagt seinen vorschlag mit einzubinden. jetzt kommst du wieder mit deinem 'reverse + reverse' daher. da kann dann jeder daher kommen und ne aenderung haben wollen. und am ende erkenne ich mein eigenes skript nicht mehr.-)
mal sehen. im moment gefaellt mir das skript so wie es ist ganz gut. es ist einfach gehalten und wenn ich in zwei jahren rein sehe werde ich auch ohne doku und komentare erkennen koennen was ich mir heute dabei gedacht habe.
aber trotzdem ein dickes danke an alle fuer die brauchbaren vorschlaege.
ct,
-
"reverse -l" ist jetzt aber ein selbstgeschriebenes Tool.
muaaahahahaa, ist ja toll das du so ein selbstgeschriebenes wasauchimmer hast, wird weder den op noch sonstirgendwen irgendwie weiterbringen *gg*
/schizo off