Mailinglist Archive: opensuse-de (4628 mails)

< Previous Next >
Re: Zeichen ersetzen in Textdatei
  • From: Achim Hoffmann <ah@xxxxxxxxxxxxx>
  • Date: Sat, 21 Sep 2002 20:17:08 +0200 (MEST)
  • Message-id: <Pine.LNX.4.33.0209212000550.28783-100000@xxxxxxxxxxxxxxxxxx>
On Fri, 20 Sep 2002, Jan Trippler wrote:

cat file|sed -e 's/ü/\\201/g'>file

Noch ein *useless use of cat award* und außerdem überschreibst Du
Dir Deine Eingabedatei. Das wird schiefgehen :-(

ok, ich gebe zu dass ich den Sonderfall "Linux *und* bash *und* File ab
bestimmter Groesse" nicht getestet habe. Schande ueber mich.
Das heisst aber nicht, dass es prinzipiell falsch ist (siehe unten).
Das Beispiel mit dem temporaeren File ist in den meisten Faellen (SHELL, OS,
grosse Files) das universellste.

So, damit ist gut, der Rest ist off-topic.

Achim

===========================================================================
Nachdem ich nun einen Award gewonnen habe, muss ich natuerlich auch eine
Rede halten, wer sich dabei durch meine bissigen und/oder sarkastischen
Bemerkungen angesprochen fuehlt, ist **selbstverstaendlich** gemeint ;-)

Vielleicht bin ich einfach zu alt fuer so moderne Sachen wie Linux und bash
und GHz-CPUs, etc., das "cat file|sed ... >file" Beispiel benutze ich seit
Jahren mit csh auf SunOS, und es funktioniert (auch Files >> 10MB).
Weil die Frage nach "ersetzen" war, und man oft keinen Platz fuer eine Kopie
hat, habe ich halt schlicht Copy&Paste gemacht, ich haette testen ... aber
das sagte ich schon. Shit happens ..
Kurz gesagt: es sollte eine Loesung sein die das File on-the-fly aendert,
ohne temporaere Kopie.

Jan, leider hast du nicht gesagt warum *dein* Beispiel mit *meinem* Vorschlag
nicht funktioniert. Es funktioniert unter bestimmten Bedingungen. Nennen wir
diese Bedingung einfach Funktion: f(SHELL,OS,CPU). Und hier eine Loesung die
mit f(bash,Linux,i386) funktioniert:

# --- (alles in einer Zeile:)
/bin/ls -l file|/bin/awk '{x=$5/8100;printf"(/bin/cat %s)",
$NF;}END{for(i=1;i<=x;i++){printf "|/bin/cat"};print "|/bin/sed -e
'"'"'s/ü/\\\\201/g'"'"'>file"}'|/bin/sh
# ---

Dieses command-line-Monstrum hat nichts mehr mit der urspruenglichen Frage
zu tun (auch wenn es dafuer funktioniert), es soll einfach nur zeigen warum
mein award-winning Vorschlag mit grossen Files nicht geht, dieses Monstrum
aber schon.
Wer genau hinschaut sieht den Grund ...
.. ich gebe nur einen Tip: 8100 ist das Ergebnis von f(bash,Linux,i386) ;-)
Ausser fuer f(*,HP-UX,*) duerfte es fuer die meisten Varianten gehen, 8100
muss halt entsprechend angepasst werden (viel Spass beim Ausprobieren).
Es soll aber nicht verschwiegen werden dass es auch hier Grenzen gibt:
user && file-sze && [u]limit && command-line buffer-size &&
#process/user && #process/system && swap-size && RAM-size && etc.
(diskutieren wir lieber nicht weiter, never-ending story ...)

Ausserdem versteht man jetzt warum ich (vielleicht) fuer den falschen Award
nomminiert wurde. Uberschreiben kann passieren (siehe oben), aber cat hat
schon seinen Sinn (zumin. in meinem Beispiel).

"cat file|sed ... >file" ist nur die Kurzform des Monstrums, und funktioniert
dann eben nur wenn alle Bedingungen erfuellt sind, was bei f(bash,Linux,i386)
leider nicht der Fall ist :-(

.. eine furchtbar umständliche Art und Weise an, mit Linux umzugehen, wenn
Ihr dauernd den cat anschmeisst.

Ich unterstelle dem Schreiber einfach, dass er den Trick nicht verstanden hat.
Schade, aber gut ich hatte es ja auch nicht explizit erklaert.
Ich haette vielleicht besser schreiben sollen:

(cat file)|sed ... >file

denn ich habe ja nicht --wie in einem anderen Posting-- geschrieben:

cat file|sed ... >tmp.file; mv tmp.file file

(das ist in der Tat ein *usless use of cat* und *useless waste of resources*)

Soweit alles klar?

Einen *useless ... award* fuer eine funktionierende (Sonder-)Loesung, muss
ich den jetzt zurueckgeben? :-]]

===========================================================================

Gut, wo wir schon bei Awards sind, dann koennte man noch den
*Don't KISS Award*
verleihen. Und zwar fuer dieses Konstrukt:

for f in `seq 1 10000`;do echo 'text'>>file;done

Ohne lange nachzudenken wuerde ich das so schreiben:

#-----------
perl -e 'print "text\n"x10000;'>file

awk 'BEGIN{for(i=1;i<=10000;i++){print "text"}}'>file

csh -c 'repeat 10000 echo "text"'>file
#-----------

KISS - keep it small and simple

Wobei KISS nicht nur was fuers Auge ist ;-)
Entscheident ist, dass alle Losungen min. Faktor 5 (csh) bis 50 (perl)
schneller sind; und das ohne das System nennenswert zu belasten (nur I/O).
Wird aus 10000 jedoch 10000000, dann wird's spannend (ausreichend swap
vorausgesetzt): perl und awk schaffen es immer noch in weniger als 1 Minute,
aber das "for .. seq .." Beispiel haengt mit grosser Wahrscheinlichkeit den
Rechner auf. Klasse.
Also man koennte das so priorisieren (diese Beispile, nicht allgemein):
csh wenn die Nachwelt verstehen soll was pasiert
perl wenn es schnell gehen soll/muss
awk wenn kein perl da ist (awk ist auf jedem UNIX)
bash wenn ich das System ins Nirvana schicken will

(-: alle 3 Beispiele funktionieren natuerlich auch unter Linux mit bash :-)

Genug fuer heute
bash# :(){ :; };:

Achim


P.S. es geht hier nicht um/gegen Linux, bash etc., sondern nur um die darin
ausgefuehrten Kommandos


< Previous Next >
Follow Ups
References