Có cách nào để sửa đổi một tập tin tại chỗ không?


54

Tôi có một tệp khá lớn (35Gb) và tôi muốn lọc tệp này tại chỗ (nghĩa là tôi không có đủ dung lượng đĩa cho một tệp khác), cụ thể là tôi muốn grep và bỏ qua một số mẫu - có cách nào để làm điều này mà không sử dụng tập tin khác?

Giả sử tôi muốn lọc ra tất cả các dòng chứa foo:ví dụ ...


3
@Tshepang: Tôi nghĩ rằng anh ấy muốn viết lại vào cùng một tập tin.
Faheem Mitha

5
"in situ" là một cụm từ tiếng Latin có nghĩa là "tại chỗ". Theo nghĩa đen, "tại vị".
Faheem Mitha

3
Trong trường hợp đó, câu hỏi nên rõ ràng hơn, giống như có cách nào để sửa đổi một tập tin tại chỗ ?
tshepang

5
@Tshepang, "in situ" là một cụm từ khá phổ biến được sử dụng trong tiếng Anh để mô tả chính xác điều đó - Tôi nghĩ rằng tiêu đề khá tự giải thích ... @Gilles, tôi cho rằng càng nhiều, càng dễ chờ thêm dung lượng đĩa! ;)
Nim

2
@Nim: Chà, tôi nghĩ tại chỗ phổ biến hơn tại chỗ .
tshepang

Câu trả lời:


41

Ở cấp độ cuộc gọi hệ thống, điều này là có thể. Một chương trình có thể mở tệp mục tiêu của bạn để viết mà không cần cắt bớt nó và bắt đầu viết những gì nó đọc từ stdin. Khi đọc EOF, tệp đầu ra có thể bị cắt ngắn.

Vì bạn đang lọc các dòng từ đầu vào, vị trí ghi tệp đầu ra phải luôn nhỏ hơn vị trí đọc. Điều này có nghĩa là bạn không nên làm hỏng đầu vào của bạn với đầu ra mới.

Tuy nhiên, tìm một chương trình làm điều này là vấn đề. dd(1)có tùy chọn conv=notrunckhông cắt bớt tệp đầu ra khi mở, nhưng nó cũng không cắt bớt ở cuối, để lại nội dung tệp gốc sau nội dung grep (với lệnh như grep pattern bigfile | dd of=bigfile conv=notrunc)

Vì nó rất đơn giản từ góc độ cuộc gọi hệ thống, tôi đã viết một chương trình nhỏ và thử nghiệm nó trên một hệ thống tập tin loopback đầy đủ (1MiB). Nó đã làm những gì bạn muốn, nhưng bạn thực sự muốn kiểm tra điều này với một số tệp khác trước. Nó luôn luôn có nguy cơ ghi đè lên một tập tin.

ghi đè

/* 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);
}

Bạn sẽ sử dụng nó như:

grep pattern bigfile | overwrite bigfile

Tôi chủ yếu đăng bài này để người khác bình luận trước khi bạn thử. Có lẽ ai đó biết về một chương trình làm một cái gì đó tương tự được thử nghiệm nhiều hơn.


Tôi muốn xem liệu tôi có thể thoát khỏi mà không viết một cái gì đó cho nó! :) Tôi đoán điều này sẽ làm các mẹo! Cảm ơn!
Nim

2
+1 cho C; có vẻ như hoạt động, nhưng tôi thấy một vấn đề tiềm ẩn: tập tin đang được đọc từ phía bên trái vào lúc đó vì bên phải đang ghi vào cùng một tập tin và trừ khi bạn phối hợp hai quy trình, bạn sẽ ghi đè lên các vấn đề có khả năng giống nhau khối. Có thể tốt hơn cho tính toàn vẹn của tệp khi sử dụng kích thước khối nhỏ hơn vì hầu hết các công cụ cốt lõi có thể sẽ sử dụng 8192. Điều này có thể làm chậm chương trình đủ để tránh xung đột (nhưng không thể đảm bảo). Có thể đọc các phần lớn hơn vào bộ nhớ (không phải tất cả) và viết thành các khối nhỏ hơn. Cũng có thể thêm một nanos ngủ (2) / us ngủ (3).
Arcege

4
@Arcege: Viết không được thực hiện trong các khối. Nếu quá trình đọc của bạn đã đọc 2 byte và quá trình ghi của bạn ghi 1 byte, chỉ byte đầu tiên sẽ thay đổi và quá trình đọc có thể tiếp tục đọc ở byte 3 với nội dung ban đầu tại điểm đó không thay đổi. Vì grepsẽ không xuất nhiều dữ liệu hơn số đọc, vị trí ghi phải luôn ở phía sau vị trí đọc. Ngay cả khi bạn đang viết ở cùng tốc độ với việc đọc, nó vẫn sẽ ổn. Hãy thử rot13 với cái này thay vì grep, và sau đó một lần nữa. md5sum trước và sau và bạn sẽ thấy nó giống nhau.
camh

6
Đẹp. Đây có thể là một bổ sung có giá trị cho nhiều hơn Jout Hess . Bạn có thể sử dụngdd , nhưng nó cồng kềnh.
Gilles 'SO- ngừng trở nên xấu xa'

'grep mẫu bigfile | ghi đè bigfile '- Tôi đã làm việc này mà không có lỗi, nhưng điều tôi không hiểu là - không phải là yêu cầu thay thế những gì trong mẫu bằng một số văn bản khác? vì vậy không nên là một cái gì đó như: 'grep mẫu bigfile | ghi đè / thay thế văn bản / bigfile '
Alexander Mills

20

Bạn có thể sử dụng sedđể chỉnh sửa các tệp tại chỗ (nhưng điều này không tạo ra một tệp tạm thời trung gian):

Để xóa tất cả các dòng có chứa foo:

sed -i '/foo/d' myfile

Để giữ tất cả các dòng có chứa foo:

sed -i '/foo/!d' myfile

Thật thú vị, liệu tệp tạm thời này có cần phải có cùng kích thước với bản gốc không?
Nim

3
Vâng, vì vậy có lẽ không tốt.
pjc50

17
Đây không phải là những gì OP yêu cầu vì nó tạo ra một tệp thứ hai.
Arcege

1
Giải pháp này sẽ thất bại trên hệ thống tệp chỉ đọc, trong đó "chỉ đọc" có nghĩa là bạn $HOME sẽ có thể ghi, nhưng /tmpsẽ chỉ đọc (theo mặc định). Chẳng hạn, nếu bạn có Ubuntu và bạn đã khởi động vào Recovery Console, đây thường là trường hợp. Ngoài ra, toán tử tài liệu ở đây <<<cũng sẽ không hoạt động ở đó, vì nó yêu cầu /tmpphải là r / w vì nó cũng sẽ ghi một tệp tạm thời vào đó. (xem câu hỏi này bao gồm straceđầu ra 'd)
cú pháp

vâng, điều này cũng không hiệu quả với tôi, tất cả các lệnh sed tôi đã thử sẽ thay thế tệp hiện tại bằng một tệp mới (mặc dù có cờ --in-place).
Alexander Mills

19

Tôi sẽ giả sử rằng lệnh bộ lọc của bạn là cái mà tôi sẽ gọi là bộ lọc thu nhỏ tiền tố , có thuộc tính mà byte N trong đầu ra không bao giờ được viết trước khi đọc ít nhất N byte đầu vào. grepcó thuộc tính này (miễn là nó chỉ lọc và không thực hiện những việc khác như thêm số dòng cho khớp). Với bộ lọc như vậy, bạn có thể ghi đè lên đầu vào khi bạn đi cùng. Tất nhiên, bạn cần chắc chắn không mắc lỗi nào, vì phần ghi đè ở đầu tập tin sẽ bị mất mãi mãi.

Hầu hết các công cụ unix chỉ đưa ra lựa chọn gắn vào tệp hoặc cắt bớt nó, không có khả năng ghi đè lên nó. Một ngoại lệ trong hộp công cụ tiêu chuẩn là dd, có thể được yêu cầu không cắt bớt tệp đầu ra của nó. Vì vậy, kế hoạch là để lọc lệnh vào dd conv=notrunc. Điều này không thay đổi kích thước của tệp, vì vậy chúng tôi cũng lấy độ dài của nội dung mới và cắt ngắn tệp theo chiều dài đó (một lần nữa với dd). Lưu ý rằng nhiệm vụ này vốn không mạnh mẽ - nếu xảy ra lỗi, bạn phải tự mình thực hiện.

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

Bạn có thể viết Perl tương đối khó khăn. Đây là một triển khai nhanh mà không cố gắng để có hiệu quả. Tất nhiên, bạn cũng có thể muốn thực hiện bộ lọc ban đầu của mình trực tiếp bằng ngôn ngữ đó.

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

16

Với bất kỳ vỏ giống như Bourne:

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

Vì một số lý do, dường như mọi người có xu hướng quên đi điều đó 40 tuổi và toán tử chuyển hướng đọc + ghi tiêu chuẩn .

Chúng tôi mở bigfileở chế độ đọc + ghi và (điều quan trọng nhất ở đây) mà không cắt ngắn stdouttrong khi bigfileđang mở (riêng) trên cat's stdin. Sau khi grepchấm dứt và nếu nó đã xóa một số dòng, stdoutbây giờ chỉ ra một nơi nào đó bên trong bigfile, chúng ta cần loại bỏ những gì vượt quá điểm này. Do đó, perllệnh cắt tệp ( truncate STDOUT) tại vị trí hiện tại (như được trả về bởi tell STDOUT).

( catdành cho GNU grep, nếu không thì sẽ phàn nàn nếu stdin và stdout trỏ đến cùng một tệp).


Chà, trong khi <>đã ở trong vỏ Bourne từ đầu những năm bảy mươi, ban đầu nó không có giấy tờ và không được thực hiện đúng . Nó không phải là bản triển khai ban đầu ashtừ năm 1989 và, trong khi đó là một shnhà điều hành chuyển hướng POSIX (từ đầu những năm 90 vì POSIX shdựa trên ksh88đó luôn luôn có nó), nó đã không được thêm vào FreeBSD shcho đến năm 2000, nên có thể là 15 năm cũ có lẽ chính xác hơn. Cũng lưu ý rằng bộ mô tả tệp mặc định khi không được chỉ định là <>trong tất cả các hệ vỏ, ngoại trừ việc ksh93nó đã thay đổi từ 0 thành 1 trong ksh93t + vào năm 2010 (phá vỡ tính tương thích ngược và tuân thủ POSIX)


2
Bạn có thể giải thích perl -e 'truncate STDOUT, tell STDOUT'? Nó làm việc cho tôi mà không bao gồm điều đó. Bất kỳ cách nào để đạt được điều tương tự mà không cần sử dụng Perl?
Aaron Blenkush

1
@AaronBlenkush, xem chỉnh sửa.
Stéphane Chazelas

1
Hoàn toàn rực rỡ - cảm ơn bạn. Lúc đó tôi đã ở đó, nhưng đừng nhớ điều này .... Một tài liệu tham khảo cho tiêu chuẩn "36 tuổi" sẽ rất vui, vì nó không được đề cập tại en.wikipedia.org/wiki/Bourne_shell . Và nó được dùng để làm gì? Tôi thấy một tham chiếu đến một sửa lỗi trong SunOS 5.6: redirection "<>" fixed and documented (used in /etc/inittab f.i.). đó là một gợi ý.
nealmcb

2
@nealmcb, xem chỉnh sửa.
Stéphane Chazelas

@ StéphaneChazelas Giải pháp của bạn so với câu trả lời này như thế nào? Nó rõ ràng làm điều tương tự nhưng trông đơn giản hơn.
akhan

9

Mặc dù đây là một câu hỏi cũ, nhưng đối với tôi, đây dường như là một câu hỏi lâu năm và một giải pháp rõ ràng, tổng quát hơn có sẵn hơn so với đề xuất cho đến nay. Tín dụng khi tín dụng đáo hạn: Tôi không chắc chắn tôi sẽ đến với nó mà không xem xét đề cập của Stéphane Chazelas về <>nhà điều hành cập nhật.

Mở một tệp để cập nhật trong trình bao Bourne là tiện ích hạn chế. Shell cung cấp cho bạn không có cách nào để tìm kiếm trên một tệp và không có cách nào để đặt độ dài mới của nó (nếu ngắn hơn tệp cũ). Nhưng điều đó dễ dàng được khắc phục, vì vậy tôi rất ngạc nhiên khi nó không nằm trong số các tiện ích tiêu chuẩn /usr/bin.

Những công việc này:

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

Cũng như điều này (mũ cho Stéphane):

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

(Tôi đang sử dụng GNU grep. Có lẽ có gì đó đã thay đổi kể từ khi anh ấy viết câu trả lời của mình.)

Ngoại trừ, bạn không có / usr / bin / ftruncate . Đối với một vài chục dòng C, bạn có thể, xem bên dưới. Tiện ích ftruncate này cắt một bộ mô tả tệp tùy ý thành một độ dài tùy ý, mặc định là đầu ra tiêu chuẩn và vị trí hiện tại.

Lệnh trên (ví dụ 1)

  • mở mô tả tập tin 4 trên Tđể cập nhật. Cũng giống như mở (2), mở tệp theo cách này đặt vị trí bù hiện tại là 0.
  • grep sau đó xử lý Tbình thường và shell chuyển hướng đầu ra của nó Tthông qua bộ mô tả 4.
  • ftruncate gọi ftruncate (2) trên bộ mô tả 4, đặt độ dài thành giá trị của phần bù hiện tại (chính xác là nơi grep rời nó).

Subshell sau đó thoát, đóng mô tả 4. Đây là 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;
}

NB, ftruncate (2) là không thể truy cập khi được sử dụng theo cách này. Để có tính tổng quát tuyệt đối, hãy đọc byte được viết cuối cùng, mở lại tệp O_WRONLY, tìm kiếm, viết byte và đóng.

Cho rằng câu hỏi là 5 tuổi, tôi sẽ nói rằng giải pháp này là không gây khó chịu. Nó tận dụng lợi thế của exec để mở một mô tả mới và <>toán tử, cả hai đều là phức tạp. Tôi không thể nghĩ ra một tiện ích tiêu chuẩn thao tác inode bằng mô tả tập tin. (Cú pháp có thể là ftruncate >&4, nhưng tôi không chắc rằng đó là một cải tiến.) Nó ngắn hơn đáng kể so với câu trả lời thăm dò, có thẩm quyền của camh. Nó chỉ rõ ràng hơn một chút so với Stéphane, IMO, trừ khi bạn thích Perl hơn tôi. Tôi hy vọng ai đó thấy nó hữu ích.

Một cách khác để làm điều tương tự sẽ là một phiên bản thực thi của lseek (2) báo cáo phần bù hiện tại; đầu ra có thể được sử dụng cho / usr / bin / truncate , mà một số Linuxi cung cấp.


5

ed có lẽ là lựa chọn đúng đắn để chỉnh sửa một tập tin tại chỗ:

ed my_big_file << END_OF_ED_COMMANDS
g/foo:/d
w
q 
END_OF_ED_COMMANDS

Tôi thích ý tưởng này, nhưng trừ khi các edphiên bản khác nhau hoạt động khác nhau ..... đây là từ 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, nếu bạn ngụ ý rằng việc lưu các thay đổi sẽ không ảnh hưởng đến tệp được đặt tên, thì bạn đã không chính xác. Tôi giải thích câu nói đó để nói rằng những thay đổi của bạn không được phản ánh cho đến khi bạn lưu chúng. Tôi thừa nhận rằng đó edkhông phải là một giải pháp gool để chỉnh sửa các tệp 35 GB vì tệp được đọc vào bộ đệm.
glenn jackman

2
Tôi đã nghĩ rằng nó có nghĩa là toàn bộ tập tin sẽ được tải vào bộ đệm .. nhưng có lẽ chỉ có phần nó được tải vào bộ đệm .. Tôi đã tò mò về ed trong một thời gian ... Tôi nghĩ rằng nó có thể thực hiện chỉnh sửa tại chỗ ... Tôi sẽ phải thử một tệp lớn ... Nếu nó hoạt động thì đó là một giải pháp hợp lý, nhưng khi tôi viết, tôi bắt đầu nghĩ rằng đây có thể là cảm hứng của sed ( được giải phóng khỏi việc làm việc với các khối dữ liệu lớn ... Tôi nhận thấy rằng 'ed' thực sự có thể chấp nhận đầu vào được truyền phát từ một tập lệnh (có tiền tố !), do đó, nó có thể có một vài thủ thuật thú vị hơn trong tay áo.
Peter.O

Tôi khá chắc chắn rằng hoạt động ghi trong việc edcắt ngắn tập tin và viết lại nó. Vì vậy, điều này sẽ không làm thay đổi dữ liệu trên đĩa tại chỗ như OP mong muốn. Ngoài ra, nó không thể hoạt động nếu tệp quá lớn để được tải vào bộ nhớ.
Nick Matteo

5

Bạn có thể sử dụng bộ mô tả tệp đọc / ghi bash để mở tệp của mình (để ghi đè lên tại chỗ), sau đó sedtruncate... nhưng tất nhiên, đừng bao giờ cho phép các thay đổi của bạn lớn hơn lượng dữ liệu đọc được cho đến nay .

Đây là tập lệnh (sử dụng: biến bash $ 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

Đây là đầu ra thử nghiệm

# 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

3

Tôi đã ánh xạ bộ nhớ tệp, thực hiện mọi thứ tại chỗ bằng cách sử dụng con trỏ char * vào bộ nhớ trần, sau đó hủy ánh xạ tệp và cắt bớt tệp.


3
+1, nhưng chỉ vì tính khả dụng rộng rãi của CPU và HĐH 64 bit cho phép thực hiện điều đó với tệp 35 GB ngay bây giờ. Những người vẫn còn trên các hệ thống 32 bit (tôi cho rằng phần lớn khán giả của trang này, tôi nghi ngờ) sẽ không thể sử dụng giải pháp này.
Warren Young

2

Không chính xác tại chỗ nhưng - điều này có thể được sử dụng trong các trường hợp tương tự.
Nếu không gian đĩa là một vấn đề, hãy nén tệp trước (vì nó là văn bản, điều này sẽ giúp giảm đáng kể) sau đó sử dụng sed (hoặc grep hoặc bất cứ thứ gì) theo cách thông thường ở giữa đường ống nén / nén.

# 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

2
Nhưng chắc chắn gzip đang ghi phiên bản nén vào đĩa trước khi thay thế bằng phiên bản nén, vì vậy bạn cần ít nhất là có thêm dung lượng, không giống như các tùy chọn khác. Nhưng sẽ an toàn hơn, nếu bạn có không gian (mà tôi không ....)
nealmcb

Đây là một giải pháp thông minh có thể được tối ưu hóa hơn nữa để chỉ thực hiện một lần nén thay vì hai lần:sed -e '/foo/d' MyFile | gzip -c >MyEditedFile.gz && gzip -dc MyEditedFile.gz >MyFile
Todd Owen

0

Vì lợi ích của bất kỳ ai googling câu hỏi này, câu trả lời chính xác là ngừng tìm kiếm các tính năng vỏ tối nghĩa có nguy cơ làm hỏng tệp của bạn để đạt được hiệu suất không đáng kể và thay vào đó sử dụng một số biến thể của mẫu này:

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

Chỉ trong tình huống cực kỳ không phổ biến rằng điều này là vì một số lý do không khả thi, bạn nên nghiêm túc xem xét bất kỳ câu trả lời nào khác trên trang này (mặc dù chúng chắc chắn rất thú vị để đọc). Tôi sẽ thừa nhận rằng câu hỏi hóc búa của OP không có dung lượng đĩa để tạo tệp thứ hai chính xác là một tình huống như vậy. Mặc dù sau đó, vẫn có các tùy chọn khác khả dụng, ví dụ như được cung cấp bởi @Ed Randall và @Basile Starynkevitch.


1
Tôi có thể hiểu sai nhưng không liên quan gì đến những gì bản gốc OP yêu cầu. aka chỉnh sửa nội tuyến của bigfile mà không có đủ dung lượng đĩa cho tệp tạm thời.
Kiwy

@Kiwy Đó là một câu trả lời nhắm vào những người xem khác của câu hỏi này (trong đó đã có gần 15.000 cho đến nay). Câu hỏi "Có cách nào để sửa đổi một tập tin tại chỗ không?" có liên quan rộng hơn trường hợp sử dụng cụ thể của OP.
Todd Owen

-3

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


3
Điều này không hoạt động nếu tệp lớn và greppeddữ liệu vượt quá độ dài của dòng lệnh cho phép. sau đó nó làm hỏng dữ liệu
Anthon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.