Gibt es eine Möglichkeit, eine Datei direkt zu ändern?

54

Ich habe eine ziemlich große Datei (35 GB) und möchte diese Datei in situ filtern (dh ich habe nicht genügend Speicherplatz für eine andere Datei). Insbesondere möchte ich einige Muster prüfen und ignorieren - gibt es eine Möglichkeit dazu? Tun Sie dies, ohne eine andere Datei zu verwenden?

Angenommen, ich möchte alle Zeilen herausfiltern, die foo:zum Beispiel Folgendes enthalten:

Nim
quelle
3
@ Tshepang: Ich denke, er möchte in dieselbe Datei zurückschreiben.
Faheem Mitha
5
"in situ" ist eine lateinische Phrase, die "an Ort und Stelle" bedeutet. Wörtlich "in Position".
Faheem Mitha
3
In diesem Fall sollte die Frage klarer sein: Gibt es eine Möglichkeit, eine Datei direkt zu ändern ?
Tshepang
5
@Tshepang, "in situ" ist eine im Englischen gebräuchliche Formulierung, um genau das zu beschreiben - ich dachte, der Titel ist ziemlich selbsterklärend ... @Gilles, so viel habe ich mir gedacht, es ist einfacher, auf mehr Speicherplatz zu warten! ;)
Nim
2
@Nim: Nun, ich denke, In-Place ist häufiger als In-Situ .
Tshepang

Antworten:

41

Auf der Systemaufrufebene sollte dies möglich sein. Ein Programm kann Ihre Zieldatei zum Schreiben öffnen, ohne sie abzuschneiden, und mit dem Schreiben beginnen, was von stdin gelesen wird. Beim Lesen von EOF kann die Ausgabedatei abgeschnitten werden.

Da Sie Zeilen aus der Eingabe herausfiltern, sollte die Schreibposition der Ausgabedatei immer kleiner als die Leseposition sein. Das heißt, Sie sollten Ihre Eingabe nicht mit der neuen Ausgabe verfälschen.

Ein Programm zu finden, das dies tut, ist jedoch das Problem. dd(1)hat die Option, conv=notruncdass die Ausgabedatei beim Öffnen nicht abgeschnitten wird, aber am Ende auch nicht abgeschnitten wird und der ursprüngliche Dateiinhalt nach dem grep-Inhalt erhalten bleibt (mit einem Befehl wie grep pattern bigfile | dd of=bigfile conv=notrunc)

Da es aus Sicht des Systemaufrufs sehr einfach ist, habe ich ein kleines Programm geschrieben und es auf einem kleinen (1 MB) Full-Loopback-Dateisystem getestet. Es hat getan, was Sie wollten, aber Sie möchten dies unbedingt zuerst mit einigen anderen Dateien testen. Es wird immer riskant sein, eine Datei zu überschreiben.

überschreiben.c

/* This code is placed in the public domain by camh */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
        int outfd;
        char buf[1024];
        int nread;
        off_t file_length;

        if (argc != 2) {
                fprintf(stderr, "usage: %s <output_file>\n", argv[0]);
                exit(1);
        }
        if ((outfd = open(argv[1], O_WRONLY)) == -1) {
                perror("Could not open output file");
                exit(2);
        }
        while ((nread = read(0, buf, sizeof(buf))) > 0) {
                if (write(outfd, buf, nread) == -1) {
                        perror("Could not write to output file");
                        exit(4);
                }
        }
        if (nread == -1) {
                perror("Could not read from stdin");
                exit(3);
        }
        if ((file_length = lseek(outfd, 0, SEEK_CUR)) == (off_t)-1) {
                perror("Could not get file position");
                exit(5);
        }
        if (ftruncate(outfd, file_length) == -1) {
                perror("Could not truncate file");
                exit(6);
        }
        close(outfd);
        exit(0);
}

Sie würden es verwenden als:

grep pattern bigfile | overwrite bigfile

Ich poste dies meistens, damit andere es kommentieren können, bevor Sie es versuchen. Vielleicht kennt jemand anderes ein Programm, das etwas Ähnliches macht, das mehr getestet wurde.

camh
quelle
Ich wollte sehen, ob ich davonkommen könnte, ohne etwas dafür zu schreiben! :) Ich denke, das wird den Trick machen! Vielen Dank!
Nim
2
+1 für C; scheint zu funktionieren, aber ich sehe ein potenzielles Problem: Die Datei wird von der linken Seite gelesen, während die rechte Seite in dieselbe Datei schreibt. Wenn Sie die beiden Prozesse nicht koordinieren, könnten Probleme möglicherweise auf derselben Seite überschrieben werden Blöcke. Für die Dateiintegrität ist es möglicherweise besser, eine kleinere Blockgröße zu verwenden, da die meisten Kerntools wahrscheinlich 8192 verwenden. Dies kann das Programm ausreichend verlangsamen, um Konflikte zu vermeiden (kann jedoch nicht garantieren). Vielleicht lesen Sie größere Teile in den Speicher (nicht alle) und schreiben Sie in kleineren Blöcken. Könnte auch einen Nanoschlaf (2) / Schlaf (3) hinzufügen.
Arcege
4
@Arcege: Das Schreiben erfolgt nicht in Blöcken. Wenn Ihr Lesevorgang 2 Bytes gelesen hat und Ihr Schreibvorgang 1 Byte schreibt, ändert sich nur das erste Byte und der Lesevorgang kann mit Byte 3 fortfahren, wobei der ursprüngliche Inhalt an diesem Punkt unverändert bleibt. Da grepnicht mehr Daten ausgegeben werden, als gelesen werden, sollte die Schreibposition immer hinter der Leseposition liegen. Auch wenn Sie mit der gleichen Geschwindigkeit wie das Lesen schreiben, ist dies in Ordnung. Versuchen Sie rot13 mit diesem anstelle von grep und dann noch einmal. md5sum das Vorher und Nachher und du wirst es gleich sehen.
camh
6
Nett. Dies ist möglicherweise eine wertvolle Ergänzung zu Joey Hess 'weiteren Funktionen . Sie können verwendendd , aber es ist umständlich.
Gilles 'SO- hör auf böse zu sein'
'grep pattern bigfile | bigfile überschreiben '- Ich habe es ohne Fehler zum Laufen gebracht, aber was ich nicht verstehe, ist, ist es nicht erforderlich, das Muster durch einen anderen Text zu ersetzen? sollte es nicht so etwas sein wie: 'grep pattern bigfile | overwrite / replace-text / bigfile '
Alexander Mills
20

Sie können sedDateien an Ort und Stelle bearbeiten (dies erstellt jedoch eine temporäre Zwischendatei):

So entfernen Sie alle Zeilen, die Folgendes enthalten foo:

sed -i '/foo/d' myfile

So behalten Sie alle Zeilen bei, die Folgendes enthalten foo:

sed -i '/foo/!d' myfile
Dogbane
quelle
Interessant, muss diese temporäre Datei die gleiche Größe wie das Original haben?
Nim
3
Ja, das ist wahrscheinlich nicht gut.
pjc50
17
Dies ist nicht das, wonach das OP fragt, da es eine zweite Datei erstellt.
Arcege
1
Diese Lösung wird auf einem schreibgeschützte Dateisystem versagen, wo „read-only“ bedeutet , dass Sie $HOME wird beschreibbar sein, sondern /tmpwird nur gelesen werden (Standardeinstellung). Wenn Sie beispielsweise Ubuntu verwenden und die Wiederherstellungskonsole gestartet haben, ist dies normalerweise der Fall. Auch der Here-Document-Operator <<<funktioniert dort nicht, da er Schreib- / Lesezugriff erfordert /tmp, da er auch eine temporäre Datei in diese Datei schreibt. (vgl. diese Frage inkl. Ausgabe)strace
Syntaxfehler
Ja, das funktioniert auch bei mir nicht. Alle sed-Befehle, die ich ausprobiert habe, ersetzen die aktuelle Datei durch eine neue a-Datei (trotz des --in-place-Flags).
Alexander Mills
19

Ich gehe davon aus, dass es sich bei Ihrem Filterbefehl um einen so genannten Prefix-Shrinking-Filter handelt , der die Eigenschaft hat, dass Byte N in der Ausgabe niemals geschrieben wird, bevor mindestens N Byte der Eingabe gelesen wurden. grephat diese Eigenschaft (solange sie nur filtert und keine anderen Aktionen wie das Hinzufügen von Zeilennummern für Übereinstimmungen ausführt). Mit einem solchen Filter können Sie die Eingabe währenddessen überschreiben. Natürlich müssen Sie darauf achten, keine Fehler zu machen, da der überschriebene Teil am Anfang der Datei für immer verloren geht.

Die meisten Unix-Tools bieten nur die Möglichkeit, eine Datei anzuhängen oder zu kürzen, ohne dass die Möglichkeit besteht, sie zu überschreiben. Die einzige Ausnahme in der Standard-Toolbox ist dd, dass die Ausgabedatei nicht gekürzt werden soll. Der Plan ist also, den Befehl zu filtern dd conv=notrunc. Die Größe der Datei ändert sich dadurch nicht. Daher ermitteln wir auch die Länge des neuen Inhalts und kürzen die Datei auf diese Länge (erneut mit dd). Beachten Sie, dass diese Aufgabe von Natur aus nicht robust ist. Wenn ein Fehler auftritt, sind Sie auf sich allein gestellt.

export LC_ALL=C
n=$({ grep -v foo <big_file |
      tee /dev/fd/3 |
      dd of=big_file conv=notrunc; } 3>&1 | wc -c)
dd if=/dev/null of=big_file bs=1 seek=$n

Sie können rau äquivalentes Perl schreiben. Hier ist eine schnelle Implementierung, die nicht versucht, effizient zu sein. Natürlich können Sie Ihre anfängliche Filterung auch direkt in dieser Sprache durchführen.

grep -v foo <big_file | perl -e '
  close STDOUT;
  open STDOUT, "+<", $ARGV[0] or die;
  while (<STDIN>) {print}
  truncate STDOUT, tell STDOUT or die
' big_file
Gilles 'SO - hör auf böse zu sein'
quelle
16

Mit jeder Bourne-ähnlichen Shell:

{
  cat < bigfile | grep -v to-exclude
  perl -e 'truncate STDOUT, tell STDOUT'
} 1<> bigfile

Aus irgendeinem Grund scheinen die Leute den 40-jährigen und standardmäßigen Lese- und Schreibumleitungsoperator zu vergessen .

Wir öffnen bigfilein Lese + Schreibmodus und (was am wichtigsten ist hier) ohne Abschneiden auf , stdoutwährend bigfilegeöffnet ist (separat) auf cat‚s stdin. Nachdem grepbeendet wurde und wenn es einige Linien entfernt hat, zeigt stdoutjetzt irgendwo innerhalb bigfile, müssen wir loswerden, was jenseits dieses Punktes ist. Daher der perlBefehl, der die Datei ( truncate STDOUT) an der aktuellen Position abschneidet (wie von zurückgegeben tell STDOUT).

(das catist für GNU grep, das sich sonst beschwert, wenn stdin und stdout auf dieselbe Datei verweisen).


¹ Nun, obwohl <>es von Anfang an in den späten siebziger Jahren in der Bourne-Shell war, war es zunächst undokumentiert und nicht richtig implementiert . Es war nicht in der ursprünglichen Implementierung ashvon 1989 enthalten und obwohl es ein POSIX- shRedirection-Operator ist (seit Anfang der 90er Jahre, da POSIX shimmer darauf basiert ksh88), wurde es sherst im Jahr 2000 zu FreeBSD hinzugefügt , also portabel für 15 Jahre alt ist wahrscheinlich genauer. Beachten Sie auch, dass der Standard-Dateideskriptor, wenn er nicht angegeben ist, <>in allen Shells enthalten ist, mit der Ausnahme, dass ksh93er 2010 in ksh93t + von 0 in 1 geändert wurde (Verstoß gegen die Abwärtskompatibilität und POSIX-Kompatibilität).

Stéphane Chazelas
quelle
2
Kannst du das erklären perl -e 'truncate STDOUT, tell STDOUT'? Es funktioniert für mich, ohne das einzuschließen. Gibt es eine Möglichkeit, dasselbe zu erreichen, ohne Perl zu verwenden?
Aaron Blenkush
1
@ AaronBlenkush, siehe Bearbeiten.
Stéphane Chazelas
1
Absolut genial - danke. Ich war damals dort, aber erinnere mich nicht daran ... Eine Referenz für den "36 Jahre alten" Standard würde Spaß machen, da sie auf en.wikipedia.org/wiki/Bourne_shell nicht erwähnt wird . Und wofür wurde es verwendet? Ich sehe einen Verweis auf eine Fehlerbehebung in SunOS 5.6: redirection "<>" fixed and documented (used in /etc/inittab f.i.). das ist ein Hinweis.
Nealmcb
2
@nealmcb, siehe bearbeiten.
Stéphane Chazelas
@ StéphaneChazelas Wie steht Ihre Lösung zu dieser Antwort ? Es macht anscheinend das Gleiche, sieht aber einfacher aus.
Akhan
9

Auch wenn dies eine alte Frage ist, scheint es mir eine mehrjährige Frage zu sein, und es gibt eine allgemeinere, klarere Lösung als bisher vorgeschlagen. Kredit, bei dem der Kredit fällig ist: Ich bin mir nicht sicher, ob ich darauf gekommen wäre, ohne Stéphane Chazelas 'Erwähnung des <>Update-Betreibers in Betracht zu ziehen .

Das Öffnen einer Datei zur Aktualisierung in einer Bourne-Shell ist von begrenztem Nutzen. Mit der Shell können Sie nicht nach einer Datei suchen und auch nicht die neue Länge festlegen (wenn sie kürzer als die alte ist). Aber das ist leicht zu beheben, so leicht bin ich überrascht, dass es nicht zu den Standard-Dienstprogrammen in gehört /usr/bin.

Das funktioniert:

$ grep -n foo T
8:foo
$ (exec 4<>T; grep foo T >&4 && ftruncate 4) && nl T; 
     1  foo

Wie das geht (Hutspitze an Stéphane):

$ { grep foo T && ftruncate; } 1<>T  && nl T; 
     1  foo

(Ich verwende GNU grep. Vielleicht hat sich etwas geändert, seit er seine Antwort geschrieben hat.)

Es sei denn, Sie haben kein / usr / bin / ftruncate . Ein paar Dutzend Zeilen von C können Sie unten sehen. Dieses Dienstprogramm ftruncate schneidet einen beliebigen Dateideskriptor auf eine beliebige Länge ab, wobei die Standardausgabe und die aktuelle Position standardmäßig verwendet werden.

Der obige Befehl (1. Beispiel)

  • Öffnet den Dateideskriptor 4 Tzum Aktualisieren. Genau wie bei open (2) positioniert das Öffnen der Datei auf diese Weise den aktuellen Offset auf 0.
  • grep wird dann Tnormal verarbeitet und die Shell leitet ihre Ausgabe Tüber den Deskriptor 4 weiter.
  • ftruncate ruft ftruncate (2) in Deskriptor 4 auf und setzt die Länge auf den Wert des aktuellen Offsets (genau dort, wo grep ihn gelassen hat).

Die Subshell wird dann beendet und der Deskriptor 4 geschlossen. Hier ist ftruncate :

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main( int argc, char *argv[] ) {
  off_t i, fd=1, len=0;
  off_t *addrs[2] = { &fd, &len };

  for( i=0; i < argc-1; i++ ) {
    if( sscanf(argv[i+1], "%lu", addrs[i]) < 1 ) {
      err(EXIT_FAILURE, "could not parse %s as number", argv[i+1]);
    }
  }

  if( argc < 3 && (len = lseek(fd, 0, SEEK_CUR)) == -1 ) {
    err(EXIT_FAILURE, "could not ftell fd %d as number", (int)fd);
  }


  if( 0 != ftruncate((int)fd, len) ) {
    err(EXIT_FAILURE, argc > 1? argv[1] : "stdout");
  }

  return EXIT_SUCCESS;
}

Hinweis: ftruncate (2) ist bei dieser Verwendung nicht portierbar. Um die absolute Allgemeinheit zu gewährleisten, lesen Sie das letzte geschriebene Byte, öffnen Sie die Datei O_WRONLY erneut, suchen Sie, schreiben Sie das Byte und schließen Sie sie.

Angesichts der Tatsache, dass die Frage 5 Jahre alt ist, werde ich sagen, dass diese Lösung nicht naheliegend ist. Es nutzt exec , um einen neuen Deskriptor und den <>Operator zu öffnen, die beide geheimnisvoll sind. Ich kann nicht an ein Standarddienstprogramm denken, das einen Inode durch Dateideskriptor manipuliert. (Die Syntax könnte lauten ftruncate >&4, aber ich bin mir nicht sicher, ob es eine Verbesserung gibt.) Sie ist erheblich kürzer als die kompetente, explorative Antwort von camh. Es ist nur ein bisschen klarer als das von Stéphane, IMO, es sei denn, Sie mögen Perl mehr als ich. Ich hoffe, jemand findet es nützlich.

Eine andere Möglichkeit wäre eine ausführbare Version von lseek (2), die den aktuellen Offset ausgibt. Die Ausgabe könnte für / usr / bin / truncate verwendet werden , was einige Linuxi bereitstellen.

James K. Lowden
quelle
5

ed ist wahrscheinlich die richtige Wahl, um eine Datei direkt zu bearbeiten:

ed my_big_file << END_OF_ED_COMMANDS
g/foo:/d
w
q 
END_OF_ED_COMMANDS
Glenn Jackman
quelle
Ich mag die Idee, aber es sei denn, verschiedene edVersionen verhalten sich unterschiedlich ..... dies ist aus man ed(GNU Ed 1.4) ...If invoked with a file argument, then a copy of file is read into the editor's buffer. Changes are made to this copy and not directly to file itself.
Peter.O
@fred, wenn Sie andeuten, dass sich das Speichern der Änderungen nicht auf die angegebene Datei auswirkt, sind Sie falsch. Ich interpretiere dieses Zitat so, dass Ihre Änderungen erst wiedergegeben werden, wenn Sie sie speichern. Ich gebe zu, dass dies edkeine Lösung für die Bearbeitung von 35-GB-Dateien ist, da die Datei in einen Puffer eingelesen wird.
Glenn Jackman
2
Ich dachte, dass es bedeutete, dass die vollständige Datei in den Puffer geladen werden würde. Aber vielleicht werden nur die Abschnitte, die benötigt werden, in den Puffer geladen. Ich war eine Weile neugierig auf ed. Ich dachte es könnte in-situ Bearbeitung tun ... ich werde nur eine versuche große Datei ... Wenn es es ist eine vernünftige Lösung funktioniert, aber wie ich schreibe, ich fange an zu glauben , dass dies auch sein mag , was inspiriert sed ( Befreit von der Arbeit mit großen Datenblöcken ... Ich habe festgestellt, dass 'ed' tatsächlich gestreamte Eingaben von einem Skript (mit vorangestelltem !) akzeptieren kann , sodass möglicherweise noch ein paar weitere interessante Tricks auf
Lager sind
Ich bin mir ziemlich sicher, dass der Schreibvorgang eddie Datei abschneidet und neu schreibt. Dies ändert also nicht die Daten auf der Festplatte an Ort und Stelle, wie es das OP wünscht. Es kann auch nicht funktionieren, wenn die Datei zu groß ist, um in den Speicher geladen zu werden.
Nick Matteo
5

Sie können einen Bash-Lese- / Schreib-Dateideskriptor verwenden, um Ihre Datei zu öffnen (um sie vor Ort zu überschreiben), sedund truncate... aber Sie dürfen natürlich niemals zulassen, dass Ihre Änderungen die bisher gelesene Datenmenge überschreiten .

Hier ist das Skript (verwendet: Bash-Variable $ BASHPID)

# Create a test file
  echo "going abc"  >junk
  echo "going def" >>junk
  echo "# ORIGINAL file";cat junk |tee >( wc=($(wc)); echo "# ${wc[0]} lines, ${wc[2]} bytes" ;echo )
#
# Assign file to fd 3, and open it r/w
  exec 3<> junk  
#
# Choose a unique filename to hold the new file size  and the pid 
# of the semi-asynchrounous process to which 'tee' streams the new file..  
  [[ ! -d "/tmp/$USER" ]] && mkdir "/tmp/$USER" 
  f_pid_size="/tmp/$USER/pid_size.$(date '+%N')" # %N is a GNU extension: nanoseconds
  [[ -f "$f_pid_size" ]] && { echo "ERROR: Work file already exists: '$f_pid_size'" ;exit 1 ; }
#
# run 'sed' output to 'tee' ... 
#  to modify the file in-situ, and to count the bytes  
  <junk sed -e "s/going //" |tee >(echo -n "$BASHPID " >"$f_pid_size" ;wc -c >>"$f_pid_size") >&3
#
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# The byte-counting process is not a child-process, 
# so 'wait' doesn't work... but wait we must...  
  pid_size=($(cat "$f_pid_size")) ;pid=${pid_size[0]}  
  # $f_pid_size may initially contain only the pid... 
  # get the size when pid termination is assured
  while [[ "$pid" != "" ]] ; do
    if ! kill -0 "$pid" 2>/dev/null; then
       pid=""  # pid has terminated. get the byte count
       pid_size=($(cat "$f_pid_size")) ;size=${pid_size[1]}
    fi
  done
  rm "$f_pid_size"
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#
  exec 3>&- # close fd 3.
  newsize=$(cat newsize)
  echo "# MODIFIED file (before truncating)";cat junk |tee >( wc=($(wc)); echo "# ${wc[0]} lines, ${wc[2]} bytes" ;echo )  cat junk
#
 truncate -s $newsize junk
 echo "# NEW (truncated) file";cat junk |tee >( wc=($(wc)); echo "# ${wc[0]} lines, ${wc[2]} bytes" ;echo )  cat junk
#
exit

Hier ist die Testausgabe

# ORIGINAL file
going abc
going def
# 2 lines, 20 bytes

# MODIFIED file (before truncating)
abc
def
c
going def
# 4 lines, 20 bytes

# NEW (truncated) file
abc
def
# 2 lines, 8 bytes
Peter.O
quelle
3

Ich würde die Datei mit einem Memory Map versehen, alles an Ort und Stelle mit char * -Pointern auf den nackten Speicher machen, dann die Zuordnung der Datei aufheben und sie abschneiden.

bmcnett
quelle
3
+1, aber nur, weil die weit verbreitete Verfügbarkeit von 64-Bit-CPUs und Betriebssystemen dies jetzt mit einer 35-GB-Datei ermöglicht. Diejenigen, die sich noch auf 32-Bit-Systemen befinden (ich vermute sogar die überwiegende Mehrheit der Besucher dieser Site), können diese Lösung nicht verwenden.
Warren Young
2

Nicht gerade vor Ort, aber - dies könnte unter ähnlichen Umständen von Nutzen sein.
Wenn der Speicherplatz ein Problem darstellt, komprimieren Sie zuerst die Datei (da dies Text ist, wird dies zu einer enormen Reduzierung führen) und verwenden Sie dann sed (oder grep oder was auch immer) auf die übliche Weise in der Mitte einer Dekomprimierungs- / Komprimierungspipeline.

# Reduce size from ~35Gb to ~6Gb
$ gzip MyFile

# Edit file, creating another ~6Gb file
$ gzip -dc <MyFile.gz | sed -e '/foo/d' | gzip -c >MyEditedFile.gz
Ed Randall
quelle
2
Aber sicher schreibt gzip die komprimierte Version auf die Festplatte, bevor sie durch die komprimierte Version ersetzt wird, sodass Sie im Gegensatz zu den anderen Optionen mindestens so viel zusätzlichen Speicherplatz benötigen. Aber es ist sicherer, wenn Sie den Raum haben (die ich nicht ....)
Nealmcb
Dies ist eine clevere Lösung, die weiter optimiert werden kann, um nur eine Komprimierung anstelle von zwei durchzuführen:sed -e '/foo/d' MyFile | gzip -c >MyEditedFile.gz && gzip -dc MyEditedFile.gz >MyFile
Todd Owen,
0

Zum Nutzen aller, die diese Frage googeln, ist die richtige Antwort, nicht mehr nach undurchsichtigen Shell-Funktionen zu suchen, die eine Beschädigung Ihrer Datei für einen vernachlässigbaren Leistungsgewinn riskieren, und stattdessen eine Variation dieses Musters zu verwenden:

grep "foo" file > file.new && mv file.new file

Nur in der äußerst ungewöhnlichen Situation, dass dies aus irgendeinem Grund nicht durchführbar ist, sollten Sie ernsthaft über eine der anderen Antworten auf dieser Seite nachdenken (obwohl sie sicherlich interessant zu lesen sind). Ich werde zugeben, dass das Rätsel des OP, keinen Speicherplatz zum Erstellen einer zweiten Datei zu haben, genau eine solche Situation ist. Obwohl es auch dann noch andere Optionen gibt, z. B. @Ed Randall und @Basile Starynkevitch.

Todd Owen
quelle
1
Ich kann falsch verstehen, aber hat nichts mit dem zu tun, was das OP ursprünglich verlangt hat. Auch bekannt als Inline-Bearbeitung von BigFile ohne genügend Speicherplatz für temporäre Dateien.
Kiwy
@ Kiwy Es ist eine Antwort, die sich an andere Zuschauer dieser Frage richtet (von denen es bisher fast 15.000 gab). Die Frage "Gibt es eine Möglichkeit, eine Datei direkt zu ändern?" hat eine größere Relevanz als der spezifische Anwendungsfall des OP.
Todd Owen
-3

echo -e "$(grep pattern bigfile)" >bigfile

user54620
quelle
3
Dies funktioniert nicht, wenn die Datei groß ist und die greppedDaten die in der Befehlszeile angegebene Länge überschreiten. es verfälscht dann die Daten
Anthon