Tại sao bạn `cat / dev / null> / var / log / message`?


77

Trên trang ví dụ kịch bản bash này , tác giả trình bày kịch bản này:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

Tại sao bạn cat /dev/nullvào bất cứ điều gì? Tôi không thể hiểu những gì dự định ở đây (nó giống như sử dụng while TRUE; sleep 1; elihwcho {some busy program}?). Tuy nhiên, tác giả gọi nó là không có gì khác thường.

Câu trả lời:


41

Bạn thường cat /dev/null > [something]khi bạn muốn xóa nội dung tệp trong khi đảm bảo hoàn toàn không có nguy cơ bị gián đoạn đến trạng thái tệp thực tế. Nội dung của tệp rõ ràng sẽ bị xóa bởi cat /dev/nullchính tệp đó khi nó tồn tại và được biết đến với hệ thống tệp mà nó cư trú trên trên vẫn sẽ ở đó với cùng số inode, quyền sở hữu và quyền.

Trong trường hợp của một tệp nhật ký, có thể là chính tệp nhật ký đó được đánh dấu là được sử dụng bởi một quy trình khác. Vì vậy, việc làm như vậy, ví dụ, vì vậy, an an rm /var/log/messages && touch /var/log/messagessẽ bị gián đoạn đối với các quy trình khác và có thể khiến các quy trình đang chạy bị nghẹt thở. Có nghĩa là một quá trình bằng cách nào đó bị khóa với một số inode cụ thể được kết nối với tệp /var/log/messagescó thể đột nhiên hoảng loạn và nói, Hey Hey! Điều gì đã xảy ra với /var/log/messages! Ngay cả khi tập tin vẫn còn đó. Chưa kể các vấn đề tiềm ẩn với quyền sở hữu và quyền được tạo lại không chính xác.

Bởi vì sự không chắc chắn này trong việc sử dụng / trạng thái của một tập tin sử dụng cat /dev/null > [something]được ưa thích bởi các quản trị viên hệ thống những người muốn hiểu rõ ràng một khúc gỗ nhưng không muốn có khả năng can thiệp vào hoạt động của các quá trình đã tồn tại.

Ngoài ra, trong ngữ cảnh của trang bạn liên kết với tác giả nêu rõ như sau:

Không có gì bất thường ở đây, chỉ có một tập hợp các lệnh có thể dễ dàng được gọi từng cái một từ dòng lệnh trên bàn điều khiển hoặc trong cửa sổ đầu cuối. Ưu điểm của việc đặt các lệnh trong một tập lệnh vượt xa việc không phải gõ lại chúng nhiều lần.

Vì vậy, không có gì khác thường mà tác giả đề cập liên quan đến toàn bộ khái niệm về tập lệnh bash cụ thể đó là gì: Nó chỉ là một tập hợp các lệnh đơn giản có thể dễ dàng chạy từ dòng lệnh nhưng được đặt trong tệp văn bản để tránh phải gõ lại chúng nhiều lần.


10
@jlliagre Điều duy nhất được "giữ sống" là bối cảnh của câu hỏi tập trung vào lý do tại sao tác giả ban đầu sẽ làm điều đó. Nếu bạn không muốn xua tan "huyền thoại", hãy đăng câu trả lời cung cấp ngữ cảnh cho phương pháp mã hóa của tác giả ban đầu cũng như quan điểm về lý do tại sao bạn tin rằng nó có thể được thay thế bằng các phương pháp khác.
JakeGould

7
Câu trả lời của @jlliagre Cyrus không giải quyết câu hỏi cốt lõi về lý do tại sao tác giả ban đầu sẽ sử dụng phương pháp đó cũng như lý do đằng sau nó. Hướng dẫn được đề cập là khá cũ và được chấp nhận hợp lý. Nó không phải là không chính xác và cũng không tồn tại một "huyền thoại đô thị". Thay vào đó là cách mã hóa một người so với cách mã hóa người khác. Đơn giản vậy thôi. Đây là một vấn đề phong cách không có tác động tiêu cực đến độ tin cậy hoặc hiệu suất.
JakeGould

3
truncate -s 0sẽ làm điều tương tự và ít thành ngữ hơn. Tuy nhiên, các lập trình viên shell là một nhóm bảo thủ và người ta có thể gặp các hệ thống đủ cũ hoặc đủ lập dị để thiếu lệnh đó.
Schwern

5
@skift cat /dev/null > /foo/barcắt ngắn tập tin; echo "" > /foo/barcắt ngắn nó và sau đó viết một ký tự dòng mới.
David

2
Một ưu điểm khác của phương pháp này so với rm & touch là quyền sở hữu và quyền được duy trì.
jjmontes

121

Tại sao bạn sẽ cat / dev / null vào bất cứ điều gì?

Bạn sẽ làm điều đó để cắt bớt nội dung tệp trong khi vẫn giữ nguyên nút inode. Tất cả các chương trình mở tệp để đọc hoặc ghi sẽ không bị ảnh hưởng ngoài thực tế kích thước tệp sẽ được đặt lại về 0.

Một thay thế không có thật thường được tìm thấy là loại bỏ tệp sau đó tạo lại nó:

rm file
touch file

hoặc tương tự:

mv file file.old
gzip file.old
touch file

Vấn đề là các phương thức này không ngăn không cho tệp cũ được ghi bởi bất kỳ quy trình nào có tệp bị xóa mở tại thời điểm xóa. Lý do tại sao trong hệ thống tệp Unix, khi bạn xóa một tệp, bạn chỉ hủy liên kết tên (đường dẫn) của nó khỏi nội dung của nó (inode). Inode được duy trì miễn là có các quá trình mở để đọc hoặc viết.

Điều này dẫn đến một số hiệu ứng tiêu cực: nhật ký được viết sau khi xóa tệp bị mất do không có cách đơn giản / di động để mở tệp bị xóa. Miễn là một quá trình ghi vào tệp bị xóa, nội dung của nó vẫn đang sử dụng không gian trên hệ thống tệp. Điều đó có nghĩa là nếu bạn xóa / tạo tệp vì nó đang lấp đầy đĩa của bạn, thì đĩa vẫn được lấp đầy. Một cách để khắc phục vấn đề sau này là khởi động lại các quy trình logger nhưng bạn có thể không muốn làm điều đó cho các dịch vụ quan trọng và nhật ký trung gian sẽ bị mất hoàn toàn. Ngoài ra còn có các tác dụng phụ do thực tế tệp bạn tạo có thể không có cùng quyền, chủ sở hữu và nhóm so với tệp gốc. Ví dụ, điều này có thể ngăn trình phân tích nhật ký đọc tệp mới tạo hoặc tệ hơn là ngăn quá trình ghi nhật ký ghi nhật ký của chính nó.

Phương pháp đầu tiên, cat /dev/null > fileđạt được mục tiêu đúng cách , tuy nhiên, mặc dù có một truyền thuyết đô thị ngoan cường, cat /dev/nullphần của nó hoàn toàn không có gì hữu ích. Nó mở một tệp giả mà trống theo thiết kế, nó không đọc được gì từ nó và cuối cùng chỉ thoát ra. Sử dụng lệnh này sau đó là lãng phí tổ hợp phím, byte, cuộc gọi hệ thống và chu kỳ CPU và nó có thể được thay thế mà không có bất kỳ thay đổi chức năng nào bằng lệnh no-op nhanh hơn :hoặc thậm chí, với hầu hết các shell, không có lệnh nào cả.

Hãy để tôi thử một phép ẩn dụ để giải thích sự vô dụng như thế nào cat /dev/null. Hãy nói rằng mục tiêu của bạn là làm trống một ly.

  • Trước tiên, bạn loại bỏ bất kỳ chất lỏng từ nó. Điều đó là đủ và chính xác là những gì ( > file) đưa ra trong thực tế các chuyển hướng luôn được xử lý trước.

  • Sau đó, bạn chọn một chai rỗng ( /dev/null) và đổ nó vào ly rỗng ( cat). Đây là bước vô nghĩa ...

Nếu bạn đọc tài liệu được liên kết của bạn đến cuối, bạn có thể nhận thấy các nhận xét trong dòng này từ phiên bản nâng cao của tập lệnh:

    cat / dev / null> wtmp #   ':> wtmp' và '> wtmp' có cùng tác dụng.

Họ thực sự có; quá xấu cat /dev/nullđã được giữ trong mã.

Điều đó có nghĩa là đoạn mã sau sẽ hoạt động với tất cả các shell thông thường (cả cshshgia đình):

cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."

và điều này sẽ làm việc với tất cả các vỏ bằng cách sử dụng cú pháp Bourne, như ash, bash, ksh, zshvà những cái tên như:

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

Tuy nhiên, xin lưu ý rằng với các shell Bourne tiền POSIX cổ, bất kỳ lệnh nào trong số này, bao gồm cat /dev/nullsẽ không cắt bớt một tệp nếu nó được viết bởi một tập lệnh shell vẫn đang chạy vào nó. Thay vì một tệp 0 byte, đó sẽ là một tệp thưa thớt với kích thước không thay đổi. Điều tương tự sẽ xảy ra nếu tệp được viết bởi một quá trình tìm kiếm đến vị trí mà nó nghĩ là vị trí hiện tại trước khi viết.

Cũng cần lưu ý rằng một số giải pháp thay thế thường được đề xuất để cắt bớt một tập tin có sai sót.

  • Cả hai điều sau đây không làm được việc. Tệp kết quả không trống nhưng chứa một dòng trống. Điều này sẽ phá vỡ các tệp nhật ký như wtmplưu trữ các bản ghi chiều rộng cố định.

    echo > file
    echo "" > file
  • Tùy chọn tiếp theo dựa trên shtùy chọn BSD không khả dụng, POSIX không chỉ định bất kỳ tùy chọn được phép nào cho tiếng vang để bạn có thể kết thúc bằng một tệp có chứa một dòng có " -n":

    echo -n > file
  • Cái đó không thể mang theo được bằng cách sử dụng shchuỗi thoát System V. Một số shell sẽ tạo một tệp chứa một dòng có " \c":

    echo "\c" > file
  • Đó là một lệnh được thiết kế để thực hiện công việc. Vấn đề đang sử dụng truncatelà không khả dụng vì lệnh này, không được chỉ định bởi POSIX, có thể bị thiếu trong hệ thống Unix / Linux.

    truncate -s 0

Cuối cùng, đây là một vài lựa chọn thay thế có thể mang theo và sẽ thực hiện đúng công việc:

  • Hoàn toàn in một chuỗi trống vào tệp:

    printf "" > file
  • Sử dụng truelệnh tương đương hoàn toàn với lệnh no-op :mặc dù dễ đọc hơn:

    true > file

1
@JonathanLeffler Tôi tin rằng đây là một phần của tất cả các cshtriển khai hiện tại mặc dù nó không nhất thiết phải được ghi lại. Từ csh trang hướng dẫn Solaris : Null command. This command is interpreted, but performs no action.. Tôi không tìm thấy đề cập nào giống nhau trong tcshtrang hướng dẫn hoặc trang BSD gốc cshnhưng cú pháp này có thể đã luôn hoạt động.
jlliagre

6
Một lý do để viết cat /dev/nulllà để làm cho ý định của bạn rõ ràng.
Davidmh

1
@Davidmh Điều đó có thể hợp lý nhưng tuyên bố của bạn không chống lại việc kiểm tra thực tế. Tôi đã quan sát thành ngữ vỏ này trong một vài thập kỷ. Khi tôi có cơ hội hỏi tác giả lý do đằng sau nó, tôi luôn có những lý thuyết không chắc chắn về việc sử dụng /dev/nullmột cách hiệu quả để tiêm byte không, dù sao cũng là một cách đáng tin cậy hơn là sử dụng :hoặc không có gì. Trong chính trang này, câu trả lời của Cyrus rất ngắn gọn nhưng đi thẳng vào vấn đề không có phiếu bầu nào trong khi JakeGould, người đang thách thức thực tế cat /dev/nulllà một người không tham gia (xem bình luận của chúng tôi) đã có ít nhất bốn phiếu.
jlliagre

2
@jlliagre kiến ​​thức về vỏ của tôi khá cơ bản, vì vậy tôi có lẽ không phải là mục tiêu dân số tốt nhất; nhưng trần >hoặc :không rõ ràng. Tôi đồng ý rằng thật là xấu hổ khi những huyền thoại đã được truyền bá do sử dụng nó.
Davidmh

4
@Davidmh Nếu bạn thực sự muốn một cái gì đó rõ ràng trước khi chuyển hướng, tôi khuyên bạn nên sử dụng printf "" > filecả hai dạng di động (POSIX) và nhẹ như thường được triển khai như một vỏ dựng sẵn.
jlliagre

6

Đó là một cách rườm rà để đưa tập tin về kích thước không.

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

Cú pháp này sẽ không hoạt động trong mọi shell.
Revierpost

2
Chính xác. Câu hỏi chỉ được gắn thẻ "bash".
Cyrus

@reinierpost Nó sẽ hoạt động trong tất cả các kiểu vỏ Bourne, phải không? Chúng ta đừng lo lắng về csh.
Barmar

: > messagescũng hoạt động. :hoặc truelà các lựa chọn rõ ràng hơn cho các lệnh không in gì và trả về true.
Peter Cordes

-3

Để cắt một tập tin đang mở. Điều này là tương đương, và dễ hiểu hơn:

echo -n > /var/log/messages

(Đã thêm -n để tránh dòng mới)


3
Điều này thực sự dễ hiểu hơn nhưng tiếc là không tương đương. Nó thậm chí sẽ phá vỡ các chức năng như trong wtmptrường hợp. Xem câu trả lời cập nhật của tôi.
jlliagre

echo -n tránh dòng mới.
bbaassssiiee

6
Nó thực sự sẽ nếu bạn chắc chắn sử dụng bash, -nnếu không thì không được đảm bảo để hoạt động trong tất cả các vỏ Bourne.
jlliagre
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.