sed tại chỗ xóa dòng trên hệ thống tập tin đầy đủ?


11

Do một lỗi ứng dụng chưa được phát hiện, tôi có hàng trăm máy chủ với một đĩa đầy đủ. Có một tệp đã được lấp đầy bằng các dòng trùng lặp, không phải là tệp nhật ký, mà là tệp môi trường người dùng với các định nghĩa khác nhau (vì vậy tôi không thể xóa tệp).

Tôi đã viết một sedlệnh đơn giản để kiểm tra các dòng được thêm sai và xóa chúng, và kiểm tra nó trên một bản sao cục bộ của tệp. Nó làm việc như dự định.

Tuy nhiên, khi tôi dùng thử trên máy chủ với toàn bộ đĩa, tôi đã gặp phải lỗi gần đây (đó là từ bộ nhớ, không sao chép và dán):

sed: couldn't flush /path/to/file/sed8923ABC: No space left on deviceServerHostname

Tất nhiên, tôi biết không còn chỗ trống. Đó là lý do tại sao tôi đang cố gắng xóa công cụ! ( sedLệnh tôi đang sử dụng sẽ giảm tập tin hơn 4000 dòng xuống còn khoảng 90 dòng.)

sedLệnh của tôi chỉ làsed -i '/myregex/d' /path/to/file/filename

Có cách nào tôi có thể áp dụng lệnh này mặc dù đĩa đầy đủ không?

(Nó phải được tự động hóa, vì tôi cần áp dụng nó cho hàng trăm máy chủ như một cách khắc phục nhanh.)

(Rõ ràng là lỗi ứng dụng cần được chẩn đoán, nhưng trong khi đó, các máy chủ không hoạt động chính xác ....)


Cập nhật: Tình huống tôi gặp phải đã được giải quyết bằng cách xóa một thứ khác mà tôi phát hiện ra mình có thể xóa, nhưng tôi vẫn thích câu trả lời cho câu hỏi này , sẽ hữu ích trong tương lai và cho những người khác.

/tmplà không đi; nó trên cùng một hệ thống tập tin.

Trước khi tôi giải phóng không gian đĩa, tôi đã kiểm tra và phát hiện ra rằng tôi có thể xóa các dòng vibằng cách mở tệp và chạy :g/myregex/dvà sau đó lưu thành công các thay đổi với :wq. Có vẻ như có thể tự động hóa việc này mà không cần dùng đến một hệ thống tệp riêng để giữ tệp tạm thời .... (?)



1
sed -itạo một bản sao tạm thời để hoạt động. Tôi nghi ngờ rằng edsẽ tốt hơn cho việc này, mặc dù tôi không đủ quen thuộc để đăng ký một giải pháp thực tế
Eric Renouf

2
Với edbạn đang chạy: printf %s\\n g/myregex/d w q | ed -s infilenhưng hãy nhớ rằng một số triển khai cũng sử dụng các tệp tạm thời giống như sed(bạn có thể thử busybox ed - afaik nó không tạo tệp tạm thời)
don_crissti

1
@Wildcard - không đáng tin cậy w / echo. sử dụng printf. và thực hiện sednối thêm một số char bạn thả ở dòng cuối cùng để bạn có thể tránh bị mất khoảng trống. Ngoài ra, trình bao của bạn cần có khả năng xử lý toàn bộ tệp trong một dòng lệnh. đó là rủi ro của bạn - thử nghiệm đầu tiên. bashđặc biệt tệ ở điều đó (tôi nghĩ rằng nó sẽ làm w / stack space?) và có thể làm bạn khó chịu bất cứ lúc nào. hai sed'si khuyến nghị ít nhất sẽ sử dụng bộ đệm ống của hạt nhân để có hiệu quả tốt giữa chúng, nhưng phương pháp này khá giống nhau. điều phụ lệnh của bạn cũng sẽ cắt bớt filecho dù sed w / in có thành công hay không.
mikeerv

1
@Wildcard - hãy thử sed '/regex/!H;$!d;x' <file|{ read v && cat >file;}và nếu nó hoạt động hãy đọc phần còn lại của câu trả lời của tôi. '
mikeerv

Câu trả lời:


10

Các -itùy chọn không thực sự ghi đè lên file gốc. Nó tạo một tệp mới với đầu ra, sau đó đổi tên thành tên tệp gốc. Vì bạn không có chỗ trên hệ thống tệp cho tệp mới này, nên nó không thành công.

Bạn sẽ cần phải tự làm điều đó trong tập lệnh của mình, nhưng tạo tệp mới trên một hệ thống tệp khác.

Ngoài ra, nếu bạn chỉ xóa các dòng khớp với biểu thức chính quy, bạn có thể sử dụng grepthay vì sed.

grep -v 'myregex' /path/to/filename > /tmp/filename && mv /tmp/filename /path/to/filename

Nói chung, hiếm khi các chương trình sử dụng cùng một tệp với đầu vào và đầu ra - ngay khi nó bắt đầu ghi vào tệp, phần chương trình đọc từ tệp sẽ không còn thấy nội dung gốc. Vì vậy, trước tiên nó phải sao chép tệp gốc ở đâu đó hoặc ghi vào tệp mới và đổi tên tệp khi hoàn tất.

Nếu bạn không muốn sử dụng tệp tạm thời, bạn có thể thử lưu trữ nội dung tệp trong bộ nhớ:

file=$(< /path/to/filename)
echo "$file" | grep -v 'myregex' > /path/to/filename

1
Nó có bảo vệ quyền, quyền sở hữu và dấu thời gian không? Có thể rsync -a --no-owner --no-group --remove-source-files "$backupfile" "$destination"từ đây
Hastur

@Hastur - bạn có nghĩa là ngụ ý rằng sed -ibảo quản những thứ đó?
mikeerv

2
@Hastur sed -ikhông bảo tồn bất kỳ thứ gì trong số đó. Tôi vừa thử nó với một tệp mà tôi không sở hữu, nhưng nằm trong một thư mục mà tôi sở hữu và nó cho phép tôi thay thế tệp đó. Việc thay thế thuộc sở hữu của tôi, không phải chủ sở hữu ban đầu.
Barmar

1
@ RalphRönnquist Để chắc chắn, bạn cần thực hiện theo hai bước:var=$(< FILE); echo "$FILE" | grep '^"' > FILE
Barmar

1
@Barmar - bạn không hoạt động - thậm chí bạn không biết bạn đã mở đầu vào thành công. Các rất ít nhất bạn có thể làm là v=$(<file)&& printf %s\\n "$v" >filenhưng bạn thậm chí không sử dụng &&. Người hỏi nói về việc chạy nó trong một kịch bản - tự động ghi đè lên một tệp với một phần của chính nó. bạn nên xác nhận ít nhất là bạn có thể mở thành công đầu vào và đầu ra. Ngoài ra, vỏ có thể phát nổ.
mikeerv

4

Đó là cách làm sedviệc. Nếu được sử dụng với -i(chỉnh sửa tại chỗ) sedsẽ tạo một tệp tạm thời với nội dung mới của tệp được xử lý. Khi hoàn tất sed, thay thế tệp làm việc hiện tại bằng tệp tạm thời. Tiện ích không chỉnh sửa tập tin tại chỗ . Đó chính xác là hành vi của mọi biên tập viên.

Giống như bạn thực hiện các tác vụ sau trong trình bao:

sed 'whatever' file >tmp_file
mv tmp_file file

Tại thời điểm này sed, cố gắng xóa dữ liệu được đệm vào tệp được đề cập trong thông báo lỗi bằng lệnh fflush()gọi hệ thống:

Đối với các luồng đầu ra, fflush()buộc ghi tất cả dữ liệu được đệm trong không gian người dùng cho luồng đầu ra hoặc luồng cập nhật đã cho thông qua chức năng ghi bên dưới của luồng.


Đối với vấn đề của bạn, tôi thấy một giải pháp trong việc gắn hệ thống tập tin separte (ví dụ a tmpfs, nếu bạn có đủ bộ nhớ hoặc thiết bị lưu trữ ngoài) và di chuyển một số tệp ở đó, xử lý chúng ở đó và di chuyển chúng trở lại.


3

Kể từ khi đăng câu hỏi này, tôi đã học được rằng đó exlà một chương trình tuân thủ POSIX. Nó hầu như được liên kết với nhau vim, nhưng dù bằng cách nào, đây là (tôi nghĩ) một điểm quan trọng exliên quan đến các hệ thống tập tin (lấy từ đặc tả POSIX):

Phần này sử dụng bộ đệm chỉnh sửa thuật ngữ để mô tả văn bản làm việc hiện tại. Không có triển khai cụ thể được ngụ ý bởi thuật ngữ này. Tất cả các thay đổi chỉnh sửa được thực hiện trên bộ đệm chỉnh sửa và không có thay đổi nào đối với nó sẽ ảnh hưởng đến bất kỳ tệp nào cho đến khi lệnh biên tập ghi tệp.

"... sẽ ảnh hưởng đến bất kỳ tệp nào ..." Tôi tin rằng việc đưa một cái gì đó vào hệ thống tệp (hoàn toàn, ngay cả một tệp tạm thời) sẽ được tính là "ảnh hưởng đến bất kỳ tệp nào." Có lẽ?*

Nghiên cứu cẩn thận của các thông số kỹ thuật POSIX choex thấy một số "gotchas" về việc sử dụng di động như dự kiến khi so sánh với mục đích sử dụng kịch bản chung của extìm thấy trực tuyến (được rải rác với các vimlệnh cụ thể.)

  1. Việc triển khai +cmdlà tùy chọn theo POSIX.
  2. Cho phép nhiều -ctùy chọn cũng là tùy chọn.
  3. Lệnh toàn cầu :g"ăn" mọi thứ cho đến dòng mới không thoát tiếp theo (và do đó chạy nó sau mỗi trận đấu được tìm thấy cho regex chứ không phải một lần ở cuối). Vì vậy, -c 'g/regex/d | x'chỉ xóa một ví dụ và sau đó thoát ra các tập tin.

Vì vậy, theo những gì tôi đã nghiên cứu, phương pháp tương thích POSIX để chỉnh sửa tại chỗ một tệp trên hệ thống tệp đầy đủ để xóa tất cả các dòng khớp với một biểu thức chính cụ thể, là:

ex -sc 'g/myregex/d
x' /path/to/file/filename

Điều này sẽ làm việc với điều kiện bạn có đủ bộ nhớ để tải tệp vào bộ đệm.

* Nếu bạn tìm thấy bất cứ điều gì chỉ ra khác, xin vui lòng, đề cập đến nó trong các ý kiến.


2
nhưng ex viết cho tmpfiles ... luôn. nó sẽ ghi bộ đệm của nó vào đĩa định kỳ. thậm chí còn có các lệnh spec'd để định vị bộ đệm tệp tmp trên đĩa.
mikeerv

@Wildcard Cảm ơn bạn đã chia sẻ, tôi đã liên kết lại tại bài viết tương tự tại SO . Tôi giả sử ex +g/match/d -scx filelà tuân thủ POSIX?
kenorb

@kenorb, không hẳn, theo cách đọc của tôi về thông số kỹ thuật, hãy xem điểm 1 của tôi trong câu trả lời ở trên. Trích dẫn chính xác từ POSIX là "Tiện ích cũ sẽ tuân thủ Nguyên tắc cú pháp tiện ích XBD, ngoại trừ việc sử dụng '-' không xác định và '+' có thể được nhận dạng là dấu phân cách tùy chọn cũng như '-'."
tự đại diện

1
Tôi không thể chứng minh điều đó, ngoại trừ bằng sự hấp dẫn theo lẽ thường, nhưng tôi tin rằng bạn đang đọc nhiều hơn về tuyên bố đó từ đặc điểm kỹ thuật hơn là thực sự ở đó. Tôi đề nghị rằng giải thích an toàn hơn là không có thay đổi nào đối với bộ đệm chỉnh sửa sẽ ảnh hưởng đến bất kỳ tệp nào tồn tại trước khi phiên chỉnh sửa bắt đầu hoặc do người dùng đặt tên. Xem thêm ý kiến ​​của tôi về câu trả lời của tôi.
G-Man nói 'Phục hồi Monica'

@ G-Man, tôi thực sự nghĩ rằng bạn đúng; giải thích ban đầu của tôi có lẽ là mơ tưởng. Tuy nhiên, kể từ khi chỉnh sửa tệp vi làm việc trên một hệ thống tệp đầy đủ, tôi tin rằng trong hầu hết các trường hợp, nó cũng sẽ hoạt động với excả một bộ phận mặc dù có thể không phải là một tệp ginormous. sed -ikhông hoạt động trên một hệ thống tập tin đầy đủ bất kể kích thước tập tin.
tự đại diện

2

Sử dụng đường ống, Luke!

Đọc tập tin | bộ lọc | viết lại

sed 's/PATTERN//' BIGFILE | dd of=BIGFILE conv=notrunc

trong trường hợp sednày không tạo ra một tệp mới và chỉ gửi đường ống đầu ra để ddmở cùng một tệp . Tất nhiên người ta có thể sử dụng greptrong trường hợp cụ thể

grep -v 'PATTERN' BIGFILE | dd of=BIGFILE conv=notrunc

sau đó cắt ngắn phần còn lại.

dd if=/dev/null of=BIGFILE seek=1 bs=BYTES_OF_SED_OUTPUT

1
Bạn có nhận thấy phần "hệ thống tập tin đầy đủ" của câu hỏi không?
tự đại diện

1
@Wildcard, có sedluôn sử dụng tệp tạm thời không? grepanyway sẽ không
Leben Gleben

Đây có vẻ là một thay thế cho spongelệnh. Có, sedvới việc -iluôn tạo các tập tin lilke "seduyUdmw" với 000 quyền.
Pablo A

1

Như đã lưu ý trong các câu trả lời khác, sed -ihoạt động bằng cách sao chép tệp vào một tệp mới trong cùng thư mục , thực hiện các thay đổi trong quy trình và sau đó di chuyển tệp mới so với tệp gốc. Đó là lý do tại sao nó không hoạt động.  ed(trình chỉnh sửa dòng gốc) hoạt động theo cách tương tự, nhưng, lần trước tôi đã kiểm tra, nó sử dụng /tmpcho tệp cào. Nếu bạn /tmpđang ở trên một hệ thống tệp khác với hệ thống tệp đầy đủ, edcó thể thực hiện công việc cho bạn.

Hãy thử điều này (tại dấu nhắc shell tương tác của bạn):

$ ed / path / to / file / tên tệp
P
g / myregex / d
w
q

Các P(mà là một vốn P) là không thực sự cần thiết. Nó bật nhắc nhở; không có nó, bạn đang làm việc trong bóng tối và một số người thấy điều này gây bối rối. Các wqw nghi thức và q UIT.

edlà nổi tiếng với chẩn đoán mật mã. Nếu tại bất kỳ thời điểm nào, nó sẽ hiển thị bất cứ điều gì khác mà dấu nhắc (đó là *) hoặc một cái gì đó rõ ràng là một xác nhận hoạt động thành công ( đặc biệt là nếu nó chứa a ?), không ghi tệp (với w). Chỉ cần bỏ ( q). Nếu nó không cho phép bạn ra ngoài, hãy thử nói qlại.

Nếu /tmpthư mục của bạn nằm trên hệ thống tệp đầy (hoặc nếu hệ thống tệp của nó cũng đầy), hãy thử tìm một khoảng trống ở đâu đó. hỗn loạn đề cập đến việc gắn một tmpfs hoặc một thiết bị lưu trữ bên ngoài (ví dụ, ổ đĩa flash); nhưng, nếu bạn có nhiều hệ thống tập tin, và họ không tất cả đầy đủ, bạn có thể chỉ cần sử dụng một trong những cái hiện có khác. hỗn loạn đề nghị sao chép (các) tệp vào hệ thống tệp khác, chỉnh sửa chúng ở đó (với sed), sau đó sao chép chúng trở lại. Tại thời điểm này, đó có thể là giải pháp đơn giản nhất. Nhưng một giải pháp thay thế sẽ là tạo một thư mục có thể ghi trên một hệ thống tệp có không gian trống, đặt biến môi trường TMPDIRđể trỏ đến thư mục đó, rồi chạy ed. (Tiết lộ: Tôi không chắc liệu điều này có hiệu quả không, nhưng nó không thể làm tổn thương.)

Khi bạn đã edlàm việc, bạn có thể tự động hóa việc này bằng cách thực hiện

ed filename << EOF
g / myregex / d
w
q
EOF

trong một kịch bản. Hoặc , theo đề xuất của don_crissti.printf '%s\n' 'g/myregex/d' w q | ed -s filename


Hừm. Điều tương tự có thể được thực hiện (với edhoặc với ex) sao cho bộ nhớ được sử dụng thay vì một hệ thống tập tin riêng biệt? Đó là những gì tôi thực sự sẽ làm (và lý do tôi không chấp nhận câu trả lời.)
Wildcard

Hừm. Điều này có thể phức tạp hơn tôi nhận ra. Tôi đã nghiên cứu nguồn gốc của ednhiều năm trước. Vẫn còn những thứ như máy tính 16 bit, trong đó các quy trình được giới hạn trong không gian địa chỉ 64K (!), Vì vậy ý ​​tưởng về một trình soạn thảo đọc toàn bộ tệp vào bộ nhớ là không bắt đầu. Kể từ đó, tất nhiên, bộ nhớ đã trở nên lớn hơn - nhưng cũng có đĩa và tệp. Vì các đĩa quá lớn, mọi người không cảm thấy cần phải đối phó với tình trạng /tmphết dung lượng. Tôi mới xem nhanh mã nguồn của một phiên bản gần đây ed, và nó vẫn có vẻ như Lọ (Cont'd)
G-Man nói 'Phục hồi Monica'

(Tiếp theo) để thực hiện bộ đệm chỉnh sửa của Google, dưới dạng tệp tạm thời, và tôi không thể tìm thấy bất kỳ dấu hiệu nào cho thấy bất kỳ phiên bản nào của ed( exhoặc vi) cung cấp tùy chọn để giữ bộ đệm trong bộ nhớ.  Mặt khác, Chỉnh sửa văn bản với ed và vi - Chương 11: Xử lý văn bản - Phần II: Khám phá Red Hat Linux - Bí mật chuyên nghiệp của Red Hat Linux 9 - Các hệ thống Linux nói rằng edbộ đệm chỉnh sửa nằm trong bộ nhớ, )
G-Man nói 'Phục hồi Monica'

(Cont'd) Xử lý và sắp chữ tài liệu UNIXUNIX của Balasubramaniam Srinivasan nói điều tương tự về vi(đó là cùng một chương trình với ex). Tôi tin rằng họ chỉ sử dụng từ ngữ cẩu thả, thiếu chính xác - nhưng, nếu nó trên Internet (hoặc in), nó phải là sự thật, phải không? Bạn trả tiền của bạn và bạn có sự lựa chọn của bạn.
G-Man nói 'Phục hồi Monica'

Nhưng dù sao, tôi đã thêm một câu trả lời mới.
G-Man nói 'Phục hồi Monica'

1

Bạn có thể cắt bớt tệp khá dễ dàng nếu bạn có thể lấy số byte để bù và dòng của bạn xuất hiện từ điểm bắt đầu đến điểm cuối.

o=$(sed -ne'/regex/q;p' <file|wc -c)
dd if=/dev/null of=file bs="$o" seek=1

Hoặc nếu không, có lẽ bạn ${TMPDIR:-/tmp}đang ở trên một số hệ thống tệp khác:

{   cut -c2- | sed "$script" >file
} <file <<FILE
$(paste /dev/null -)
FILE

Bởi vì (hầu hết) các trình bao đặt các tài liệu ở đây trong một tệp tạm thời đã bị xóa. Nó hoàn toàn an toàn miễn là bộ <<FILEmô tả được duy trì từ đầu đến cuối và ${TMPDIR:-/tmp}có nhiều không gian như bạn cần.

Các vỏ không sử dụng tệp tạm thời sử dụng đường ống và do đó không an toàn khi sử dụng theo cách này. Những vỏ thường ashdẫn xuất như busybox, dash, BSD sh- zsh, bash, ksh, và Bourne shell, tuy nhiên, tất cả các file sử dụng tạm thời.

Rõ ràng tôi đã viết một chương trình vỏ nhỏ vào tháng 7 năm ngoái để làm một cái gì đó rất giống như thế này


Nếu /tmpkhông khả thi, thì miễn là bạn có thể đặt tệp vào bộ nhớ một cái gì đó như ...

sed 'H;$!d;x' <file | { read v &&
sed "$script" >file;}

... Như một trường hợp chung ít nhất sẽ đảm bảo rằng tệp được đệm hoàn toàn bởi sedquy trình đầu tiên trước khi cố gắng cắt bớt tệp vào / ra.

Một giải pháp được nhắm mục tiêu hơn - và hiệu quả hơn có thể là:

sed '/regex/!H;$!d;x' <file|{ read v && cat >file;}

... bởi vì nó sẽ không làm phiền đến các dòng đệm mà bạn muốn xóa.

Một bài kiểm tra của trường hợp chung:

{   nums=/tmp/nums
    seq 1000000 >$nums
    ls -lh "$nums"
    wc -l  "$nums"
    sed 'H;$!d;x' <$nums | { read script &&  ### read always gets a blank
    sed "$script" >$nums;}
    wc -l  "$nums"
    ls -lh "$nums"
}

-rw-r--r-- 1 mikeserv mikeserv 6.6M Dec 22 20:26 /tmp/nums
1000000 /tmp/nums
1000000 /tmp/nums
-rw-r--r-- 1 mikeserv mikeserv 6.6M Dec 22 20:26 /tmp/nums

Tôi thú nhận rằng tôi đã không đọc chi tiết câu trả lời của bạn trước đây, bởi vì nó bắt đầu bằng các giải pháp không thể thực hiện được (đối với tôi) liên quan đến số byte (khác nhau giữa mỗi máy chủ) và /tmptrên cùng một hệ thống tệp. Tôi thích sedphiên bản kép của bạn . Tôi nghĩ rằng sự kết hợp giữa Barmar và câu trả lời của bạn có lẽ là tốt nhất, đại loại như: myvar="$(sed '/myregex/d' < file)" && [ -n "$myvar" ] && echo "$myvar" > file ; unset myvar (Trong trường hợp này tôi không quan tâm đến việc giữ nguyên các dòng mới.)
Wildcard

2
@Wildcard - đó có thể là. nhưng bạn không nên sử dụng shell như cơ sở dữ liệu. những sed| catđiều ở trên không bao giờ mở đầu ra trừ khi sedđã đệm toàn bộ tệp và sẵn sàng bắt đầu ghi tất cả vào đầu ra. Nếu nó cố gắng đệm tệp và thất bại - readkhông thành công vì tìm thấy EOF trên |đường ống trước khi nó đọc dòng mới đầu tiên của nó và do đó cat >out không bao giờ xảy ra cho đến khi hoàn toàn ghi nó ra khỏi bộ nhớ. một tràn hoặc bất cứ điều gì như nó chỉ thất bại. toàn bộ đường ống trả lại thành công hay thất bại mọi lúc. lưu trữ nó trong một var chỉ là rủi ro hơn.
mikeerv

@Wildcard - nếu tôi thực sự muốn nó trong một biến, tôi nghĩ id làm như file=$(sed '/regex/!H;$!d;x' <file | read v && tee file) && cmp - file <<<"$file" || shitevậy : vì vậy tệp đầu ra và var sẽ được ghi đồng thời, điều này sẽ tạo ra một hoặc một bản sao lưu hiệu quả , đó là lý do duy nhất bạn muốn làm phức tạp mọi thứ hơn bạn cần.
mikeerv

@mikeerv: Hiện tại tôi đang xử lý vấn đề tương tự như OP và tôi thấy giải pháp của bạn thực sự hữu ích. Nhưng tôi không hiểu cách sử dụng read scriptread vtrong câu trả lời của bạn. Nếu bạn có thể nói rõ hơn về nó, tôi sẽ được đánh giá cao, cảm ơn!
sylye

1
@sylye - $scriptsedtập lệnh bạn sẽ sử dụng để nhắm mục tiêu bất kỳ phần nào trong tệp bạn muốn; kịch bản của nó mang lại cho bạn kết quả cuối cùng mà bạn muốn trong luồng. vchỉ là một giữ chỗ cho một dòng trống. trong bashshell không cần thiết vì bashsẽ tự động sử dụng $REPLYbiến shell thay cho nó nếu bạn không chỉ định một biến, nhưng POSIXly bạn nên luôn luôn làm như vậy. Nhân tiện, tôi rất vui vì bạn thấy nó hữu ích. Chúc may mắn với điều đó. im mikeerv @ gmail nếu bạn cần bất cứ điều gì chuyên sâu. tôi sẽ có một máy tính một lần nữa sau vài ngày
mikeerv

0

Câu trả lời này mượn ý tưởng từ câu trả lời khác nàycâu trả lời khác nhưng dựa trên chúng, tạo ra một câu trả lời thường được áp dụng hơn:

num_bytes = $ (sed '/ myregex / d' / path / to / file / tên tệp | wc -c)
sed '/ myregex / d' / path / to / file / filename 1 <> / path / to / file / filename 
dd if = / dev / null of = / path / to / file / filename bs = "$ num_bytes" = 1

Dòng đầu tiên chạy sedlệnh với đầu ra được ghi vào đầu ra tiêu chuẩn (chứ không phải vào một tệp); cụ thể, đến một đường ống wcđể đếm các ký tự. Dòng thứ hai cũng chạy sedlệnh với đầu ra được ghi thành đầu ra tiêu chuẩn, trong trường hợp này được chuyển hướng đến tệp đầu vào ở chế độ đọc / ghi đè (không cắt bớt), được thảo luận ở đây . Đây là một điều nguy hiểm để làm; nó chỉ an toàn khi lệnh bộ lọc không bao giờ tăng lượng dữ liệu (văn bản); tức là, với mỗi n byte mà nó đọc, nó ghi n hoặc ít byte hơn. Tất nhiên, điều này đúng với sed '/myregex/d'lệnh; đối với mỗi dòng mà nó đọc, nó viết chính xác cùng một dòng hoặc không có gì. (Những ví dụ khác:s/foo/fu/hoặc s/foo/bar/sẽ an toàn, nhưng s/fu/foo/s/foo/foobar/sẽ không.)

Ví dụ:

$ cat filename
It was
a dark and stormy night.
$ sed '/was/d' filename 1<> filename
$ cat filename
a dark and stormy night.
night.

bởi vì 32 byte dữ liệu này:

I  t     w  a  s \n  a     d  a  r  k     a  n  d     s  t  o  r  m  y     n  i  g  h  t  . \n

đã bị ghi đè với 25 ký tự này:

a     d  a  r  k     a  n  d     s  t  o  r  m  y     n  i  g  h  t  . \n

để lại bảy byte night.\ncòn lại ở cuối.

Cuối cùng, ddlệnh tìm kiếm đến cuối dữ liệu mới, được lọc (byte 25 trong ví dụ này) và loại bỏ phần còn lại của tệp; tức là, nó cắt tập tin tại thời điểm đó.


Nếu, vì bất kỳ lý do nào, 1<>thủ thuật không hoạt động, bạn có thể làm

sed '/ myregex / d' / path / to / file / tên tệp | dd của = / path / to / file / tên tệp conv = notrunc

Ngoài ra, lưu ý rằng, miễn là tất cả những gì bạn đang làm là xóa các dòng, tất cả những gì bạn cần là grep -v myregex(như được chỉ ra bởi Barmar ).


-3

sed -i 'd' / path / to / file / tên tệp


1
Chào! Tốt nhất nên giải thích chi tiết nhất có liên quan đến cách giải pháp của bạn hoạt động và trả lời câu hỏi.
dhag

2
Đây là một câu trả lời không khủng khiếp. (a) Nó sẽ thất bại trên một hệ thống tập tin đầy đủ, giống như lệnh ban đầu của tôi; (b) Nếu thành công, nó sẽ xóa tệp WHOLE, thay vì chỉ các dòng khớp với biểu thức chính quy của tôi.
tự đại diện
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.