Sự khác biệt giữa con mèo và '>' để loại bỏ một tập tin


23

Hai lệnh này có khác nhau về cách chúng đi về các tập tin không? Là cái sau một cách ngắn hơn để làm cái trước? Điều gì đang xảy ra đằng sau hậu trường?

Cả hai

$ cat /dev/null > file.txt

$ > file.txt 

năng suất

-rw-r--r--  1 user  wheel  0 May 18 10:33 file.txt

Câu trả lời:


28

cat /dev/null > file.txtlà một công dụng vô dụng của con mèo .

Về cơ bản cat /dev/nullchỉ đơn giản là kết quả đầu catra không có gì. Vâng, nó hoạt động, nhưng nó được nhiều người cau mày vì nó dẫn đến việc gọi một quy trình bên ngoài không cần thiết.
Đó là một trong những điều phổ biến đơn giản vì nó phổ biến.

Sử dụng chỉ > file.txtsẽ hoạt động trên hầu hết các vỏ, nhưng nó không hoàn toàn di động. Nếu bạn muốn hoàn toàn di động, sau đây là những lựa chọn thay thế tốt:

true > file.txt
: > file.txt

Cả hai :trueđầu ra đều không có dữ liệu và là các phần tử dựng sẵn (trong khi đó catlà một tiện ích bên ngoài), do đó chúng nhẹ hơn và 'phù hợp' hơn.

 

Cập nhật:

Như tylerl đã đề cập trong bình luận của mình, đó cũng là >| file.txtcú pháp.

Hầu hết các shell đều có một cài đặt sẽ ngăn chúng cắt xén một tệp hiện có thông qua >. Bạn phải sử dụng >|thay thế. Điều này là để ngăn chặn lỗi của con người khi bạn thực sự có ý định nối thêm >>. Bạn có thể bật hành vi với set -C.

Vì vậy, với điều này, tôi nghĩ rằng phương pháp đơn giản nhất, phù hợp nhất và di động để cắt xén một tệp sẽ là:

:>| file.txt

2
Lệnh dấu hai chấm được định nghĩa trong POSIX . Đó là một hoạt động null tồn tại để mở rộng dòng lệnh args.
kojiro

3
LOL, "lạm dụng mèo"
KM.

2
@kojiro :cũng được POSIX ủy quyền tích hợp và trên thực tế khác với trueviệc nó được coi là tích hợp "đặc biệt" .
jw013

2
đừng quên về noclobber . >| filelà một cắt ngắn rõ ràng hơn.
tylerl

1
Không truebắt buộc phải được xây dựng và theo truyền thống thì không. :được xây dựng trong tất cả các vỏ của gia đình Bourne. :là một nội dung đặc biệt trên mỗi POSIX (vì vậy : > filesẽ thoát khỏi shell chẳng hạn nếu filekhông thể mở để viết bằng shell POSIX) và truekhông. POSIX thậm chí còn đề cập đến việc :có thể hiệu quả hơn truetrên một số hệ thống.
Stéphane Chazelas

23

Về tính di động:

                      Bourne POSIX  zsh    csh/tcsh  rc/es  fish
> file                Y      Y      N(1)   N(1)      N      N
: > file              N/Y(2) Y(3)   Y      Y(4)      N(5)   N(5)
true > file           Y(5)   Y      Y      Y(5)      Y(5)   Y(5)
cat /dev/null > file  Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
eval > file           Y(3,8) Y(3)   Y      Y(6)      Y      Y
cp /dev/null file (7) Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
printf '' > file      Y(5)   Y      Y      Y(5)      Y(5)   Y

Ghi chú:

  1. ngoại trừ trong shhoặc kshmô phỏng, đối với các chuyển hướng không có lệnh, trong zsh, một lệnh mặc định được giả sử (một máy nhắn tin chỉ chuyển hướng stdin, catnếu không), có thể được điều chỉnh bằng các biến NULLCMD và READNULLCMD. Đó là cảm hứng từ tính năng tương tự trong(t)csh
  2. Các chuyển hướng ban đầu không được thực hiện :trong UnixV7 như :đã được giải thích nửa chừng giữa một nhà lãnh đạo bình luận và một lệnh null. Sau đó, chúng giống như tất cả các nội trang, nếu chuyển hướng thất bại, nó thoát khỏi vỏ.
  3. :evalđược tích hợp đặc biệt, nếu chuyển hướng không thành công, nó sẽ thoát khỏi vỏ ( bashchỉ thực hiện điều đó ở chế độ POSIX).
  4. Thật thú vị, trong (t)cshđó, đó là xác định một nhãn null (cho goto), vì vậy goto ''sẽ có chi nhánh ở đó. Nếu chuyển hướng thất bại, nó thoát khỏi vỏ.
  5. Trừ khi / nếu lệnh tương ứng có sẵn trong $PATH( :thường không phải là; true, cat, cpprintfnói chung là (POSIX đòi hỏi chúng)).
  6. Nếu chuyển hướng thất bại, nó thoát khỏi vỏ.
  7. fileTuy nhiên, nếu là một liên kết tượng trưng đến một tệp không tồn tại, một số cptriển khai như GNU sẽ từ chối tạo nó.
  8. Các phiên bản ban đầu của shell Bourne không hỗ trợ chuyển hướng các nội dung

Về tính dễ đọc:

(phần này rất chủ quan)

  • > file. Điều đó >trông quá giống như một lời nhắc hoặc một nhận xét. Ngoài ra câu hỏi tôi sẽ hỏi khi đọc rằng (và hầu hết các shell sẽ phàn nàn về điều tương tự) là đầu ra chính xác mà bạn đang chuyển hướng? .
  • : > file. :được gọi là lệnh no-op. Vì vậy, nó đọc ngay lập tức như tạo ra một tập tin trống. Tuy nhiên, ở đây một lần nữa, điều đó :có thể dễ dàng bị bỏ qua và / hoặc được xem như một lời nhắc.
  • true > file: boolean có liên quan gì đến nội dung chuyển hướng hoặc tệp? Có nghĩa là gì ở đây? là điều đầu tiên tôi nghĩ đến khi tôi đọc nó.
  • cat /dev/null > file. Liên /dev/nullkết thành file? catđược thường được xem như lệnh để đổ nội dung của các tập tin, mà vẫn có thể có ý nghĩa: đổ nội dung của các tập tin rỗng vàofile , một chút giống như một cách phức tạp để nói cp /dev/null filenhưng vẫn hiểu.
  • cp /dev/null file. Sao chép nội dung của tập tin trống vào file. Có ý nghĩa, mặc dù ai đó không biết làm thế nào cpđể làm theo mặc định có thể nghĩ rằng bạn cũng đang cố gắng tạo ra filemột nullthiết bị.
  • eval > filehoặc eval '' > file. Chạy không có gì và chuyển hướng đầu ra của nó đến a file. Có nghĩa với tôi. Kỳ lạ là nó không phải là một thành ngữ phổ biến.
  • printf '' > file: in rõ ràng không có gì vào một tập tin. Một trong đó có ý nghĩa nhất đối với tôi.

Về mặt hiệu suất

Sự khác biệt sẽ là liệu chúng ta có sử dụng shell dựng hay không. Nếu không, một tiến trình phải được rẽ nhánh, lệnh được tải và thực thi.

evalđược đảm bảo được xây dựng trong tất cả các vỏ. :được tích hợp sẵn ở bất cứ nơi nào có sẵn (Bourne / csh thích). trueđược tích hợp sẵn trong vỏ giống như Bourne.

printfđược tích hợp trong hầu hết các vỏ giống như Bourne hiện đại và fish.

cpcatthường không được tích hợp sẵn.

Bây giờ cp /dev/null filekhông gọi chuyển hướng vỏ, vì vậy những thứ như:

find . -exec cp /dev/null {} \;

sẽ hiệu quả hơn:

find . -exec sh -c '> "$1"' sh {} \;

(mặc dù không nhất thiết phải hơn:

find . -exec sh -c 'for f do : > "$f"; done' sh {} +

).

Cá nhân

Cá nhân, tôi sử dụng : > filetrong các vỏ giống như Bourne, và không sử dụng bất cứ thứ gì khác ngoài các vỏ giống như Bourne ngày nay.


Thế còn dd of=file count=0?
kojiro

2
@kojiro, với một số triển khai dd(như ít nhất là của Solaris 10), count=0bị bỏ qua. dd if=/dev/null of=filesẽ di động hơn. Trong mọi trường hợp, đó là độc lập với vỏ.
Stéphane Chazelas

OK, nhưng nó không kém phần xứng đáng để đưa vào cp /dev/null file, phải không?
kojiro

2
@kojiro, cp /dev/null filelà một thành ngữ phổ biến. Tôi giới hạn ở những điều đó, vấn đề không phải là liệt kê tất cả các cách có thể.
Stéphane Chazelas

5

Bạn có thể muốn xem xét truncate, chính xác là: cắt bớt một tập tin.

Ví dụ:

truncate --size 0 file.txt

Điều này có lẽ chậm hơn so với sử dụng true > file.txt.

Tuy nhiên, điểm chính của tôi là: truncateđược dùng để cắt các tệp, trong khi sử dụng> có tác dụng phụ là cắt bớt tệp.


2
Truncate thật tuyệt khi bạn muốn cắt một tệp thành một thứ khác 0. Điều đó nói rằng, ngay cả khi không có shell là một câu lệnh lạ: bạn có thể mô tả một bối cảnh truncatesẽ có sẵn, nhưng thư viện C >cũng không unistdcó sẵn?
kojiro

Không hẳn vậy. Có lẽ có một giải pháp thanh lịch hơn cho mọi kịch bản hoặc ngôn ngữ lập trình có sẵn.
Fabian

3
truncatelà một tiện ích FreeBSD, tương đối gần đây (2008) được thêm vào lõi GNU (mặc dù --sizekiểu tùy chọn dài GNU là đặc trưng của GNU), do đó, nó không có sẵn trong các hệ thống không phải GNU hoặc FreeBSD và nó không có sẵn trong các hệ thống GNU cũ hơn, Tôi sẽ không nói nó di động. cp /dev/null filesẽ làm việc mà không cần chuyển hướng vỏ và sẽ dễ mang theo hơn.
Stéphane Chazelas

Được rồi, tôi sẽ loại bỏ nhận xét tính di động đó. Mặc dù định nghĩa của bạn gần đây dường như khác nhau.
Fabian

2

Câu trả lời phụ thuộc một chút vào cái gì file.txtvà quá trình viết nó như thế nào!

Tôi sẽ trích dẫn một trường hợp sử dụng phổ biến: bạn có một logfile đang phát triển file.txtvà muốn xoay nó.

Vì vậy, bạn sao chép, ví dụ, file.txtvào file.txt.save, sau đó cắt ngắn file.txt.

Trong trường hợp này, NẾU tệp không được mở bằng another_process(ví dụ: another_processcó thể là chương trình xuất ra tệp đó, ví dụ: chương trình ghi nhật ký gì đó), thì 2 đề xuất của bạn là tương đương và cả hai đều hoạt động tốt (nhưng thứ 2 được ưu tiên là "cat / dev / null> file.txt" đầu tiên là cách sử dụng Cat vô dụng và cũng mở và đọc / dev / null).

Nhưng rắc rối thực sự sẽ xảy ra nếu other_processnó vẫn hoạt động và vẫn có một tay cầm mở đi đến file.txt.

Sau đó, 2 trường hợp chính phát sinh, tùy thuộc vào cách other processmở tệp:

  • Nếu other_processmở nó theo cách thông thường, thì tay cầm sẽ vẫn trỏ đến vị trí cũ trong tệp, ví dụ như ở offset 1200 byte. Do đó, lần ghi tiếp theo sẽ bắt đầu ở offset 1200 và do đó, bạn sẽ lại có một tệp 1200byte (+ bất cứ thứ gì khác được viết), với 1200 ký tự null hàng đầu! Không phải những gì bạn muốn , tôi đoán.

  • Nếu other_processđược mở file.txttrong "chế độ chắp thêm", thì mỗi lần nó ghi, con trỏ sẽ chủ động tìm đến cuối tệp. Do đó, khi bạn cắt bớt nó, nó sẽ "tìm kiếm" cho đến khi byte 0 và bạn sẽ không có tác dụng phụ xấu! Đây là những gì bạn muốn (... thông thường!)

Lưu ý rằng điều này có nghĩa là bạn cần, khi bạn cắt một tệp, để đảm bảo rằng tất cả other_processvẫn đang ghi vào vị trí đó đã mở nó trong chế độ "chắp thêm". Nếu không, bạn sẽ cần phải dừng other_processchúng lại và khởi động lại chúng để chúng bắt đầu chỉ vào phần đầu của tệp thay vì vị trí cũ.

Tài liệu tham khảo: /programming//a/16720582/1841533 để được giải thích rõ ràng hơn và một ví dụ ngắn về sự khác biệt giữa ghi nhật ký chế độ bình thường và chắp thêm tại /programming//a/984761/1841533


2
Rất ít câu trả lời này thực sự có liên quan đến hoặc trả lời câu hỏi. Sự khác biệt giữa a cat /dev/null > filevà a > filelà a cat /dev/nullvà điều đó không tạo ra sự khác biệt cho tệp.
jw013

@ jw013: Đúng! Nhưng tôi chỉ muốn nhân cơ hội của câu hỏi để nêu lại thông tin "những gì bạn muốn / không phải những gì bạn muốn", vì nó không được biết đến nhiều, và có thể đánh vào một ai đó đang cố gắng xoay vòng nhật ký (một trường hợp phổ biến mà bạn muốn cắt ngắn một tập tin).
Olivier Dulac

1
Có thời gian và địa điểm cho mọi việc. Thông tin của bạn có thể hữu ích trong một số ngữ cảnh khác nhưng nó không thuộc về nơi này - bạn nên tìm một nơi thích hợp hơn cho nó bởi vì không ai cố gắng xoay các bản ghi sẽ tìm kiếm trong câu hỏi chuyển hướng hoàn toàn không liên quan này. Ở đây câu trả lời của bạn tương đương với một loại cỏ kỹ thuật số, giống như một cây bí ngô hữu ích khác ở giữa cánh đồng ngô sẽ được coi là một loại cỏ dại.
jw013

1

Tôi thích điều này và sử dụng nó thường xuyên vì nó trông sạch sẽ hơn và không giống như ai đó vô tình nhấn phím quay lại:

echo -n "" > file.txt

Có nên tích hợp quá không?


3
Có nhiều cách để loại bỏ một tập tin. Tôi nghĩ rằng KM. chỉ quan tâm đến việc hiểu sự khác biệt giữa hai phương pháp được hiển thị trong câu hỏi.
drs

6
Nhiều echotriển khai không hỗ trợ -n(và sẽ xuất ra -n<SPC><NL>ở đây. printf '' > file.txtSẽ dễ mang theo hơn (ít nhất là trên các hệ thống hiện đại / POSIX).
Stéphane Chazelas
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.