mv một tập tin thành / dev / null phá vỡ dev / null


25

Nếu tôi làm: touch file; mv file /dev/nullnhư root, /dev/nullbiến mất. ls -lad /dev/nullkết quả là không có tập tin hoặc thư mục như vậy. Điều này phá vỡ các ứng dụng phụ thuộc vào /dev/nullnhư SSH và có thể được giải quyết bằng cách thực hiện mknod /dev/null c 1 3; chmod 666 /dev/null. Tại sao việc di chuyển một tệp thông thường sang tệp đặc biệt này dẫn đến sự biến mất của /dev/null?

Để làm rõ, đây là mục đích thử nghiệm và tôi hiểu cách mvhoạt động của lệnh. Điều tôi tò mò là tại sao ls -la /dev/nulltrước khi thay thế nó bằng một tệp thông thường sẽ hiển thị đầu ra dự kiến, nhưng sau đó nó cho thấy /dev/nullnó không tồn tại mặc dù một tệp được cho là được tạo thông qua mvlệnh gốc và lệnh tệp hiển thị Văn bản ASCII. Tôi nghĩ rằng đây phải là sự kết hợp của lshành vi lệnh kết hợp với devfskhi một tệp không đặc biệt thay thế một ký tự / tệp đặc biệt. Đây là trên Mac OS X, các hành vi có thể khác nhau trên các hệ điều hành khác.


44
Đừng lộn xộn với /dev/null.
devnull

7
@devnull nói
Braiam

3
Cách thích hợp để xóa các tập tin là rmlệnh.
casey

1
Có vẻ như đó là gốc rễ của vấn đề của bạn, OSX devfshài hước về các tệp bình thường. Lạ là bạn đã không nhận được một lỗi từ mvmặc dù. Làm thế nào về cách này : touch testfile; mv testfile /dev?
Graeme

3
@Gregg, mvchỉ có thể là nguyên tử trên cùng một hệ thống tập tin.
Graeme

Câu trả lời:


16

Nhìn vào mã nguồn cho mv, http://www.opensource.apple.com/source/file_cmds/file_cmds-220.7/mv/mv.c :

/*
 * If rename fails because we're trying to cross devices, and
 * it's a regular file, do the copy internally; otherwise, use
 * cp and rm.
 */
if (lstat(from, &sb)) {
    warn("%s", from);
    return (1);
}
return (S_ISREG(sb.st_mode) ?
    fastcopy(from, to, &sb) : copy(from, to));

...

int
fastcopy(char *from, char *to, struct stat *sbp)
{
...
while ((to_fd =
    open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) {
        if (errno == EEXIST && unlink(to) == 0)
            continue;
        warn("%s", to);
        (void)close(from_fd);
        return (1);
}

Trong lần đầu tiên đi qua vòng lặp while, open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)sẽ thất bại với EEXIST. Sau đó /dev/nullsẽ được bỏ liên kết và vòng lặp được lặp lại. Nhưng như bạn đã chỉ ra trong nhận xét của mình, các tệp thông thường không thể được tạo trong đó /dev, vì vậy trong lần tiếp theo qua vòng lặp, open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)vẫn sẽ thất bại.

Tôi muốn gửi báo cáo lỗi với Apple. Các mvmã nguồn chủ yếu là thay đổi so với phiên bản FreeBSD, nhưng vì devfs OSX của có hành vi phi POSIX với các tập tin thường xuyên, Apple nên sửa chữa của họ mv.


1
Tôi đang đưa ra câu trả lời tốt nhất này ngay bây giờ để cung cấp mã nguồn và thừa nhận đây là một lỗi, đó là những gì tôi đang lái xe.
Gregg Leventhal

12

Di chuyển tệp đến vị trí của tệp đã có thay thế tệp hiện có. Trong trường hợp này, /dev/nulltập tin thiết bị được thay thế, giống như bất kỳ tập tin bình thường nào. Để tránh điều này, hãy sử dụng tùy chọn -i(tương tác, cảnh báo trước khi ghi đè) hoặc -n(không có clober) cho mv.

/dev/nullchỉ thực hiện chức năng đặc biệt của nó như một thùng bit sau đó thiết bị được mở như vậy. Ví dụ, khi >toán tử shell được sử dụng, tệp sẽ được mở sau đó cắt ngắn (không loại bỏ thay thế, có thể là những gì bạn mong đợi). Như casey đã đề cập, cách chính xác để xóa một tệp là bằng rmhoặc thậm chí với unlink.


Xem ý kiến ​​của tôi để terdon.
Gregg Leventhal

Hiểu rồi, -d là không cần thiết, đó chỉ là một thói quen xấu tuy nhiên tập tin vẫn sẽ hiển thị trong đầu ra ls, nó không nên hiển thị là không tồn tại.
Gregg Leventhal

@Graeme - Chào mừng bạn đến 3K, làm tốt lắm!
slm

10

Umm, vì bạn ghi đè tập tin đặc biệt với tập tin bình thường? Bạn đã mong đợi điều gì xảy ra? dev/nullkhông phải là một thư mục, nó là một tập tin trỏ đến một nullthiết bị. Khi bạn mvmột cái gì đó với nó, bạn xóa bản gốc và thay thế nó bằng bất cứ thứ gì bạn di chuyển:

$ file /dev/null 
/dev/null: character special 
$ sudo mv file /dev/null 
$ file /dev/null 
/dev/null: ASCII text

2
Nhưng tôi đang nói / dev / null hiển thị là thiếu khi chạy ls -lad / dev / null. Đây phải là một cái gì đó cụ thể cho các devfs, đó là những gì tôi muốn biết về.
Gregg Leventhal

Nếu tôi mv tập tin / dev / null thì / dev / null sẽ chứa những gì tập tin chứa nhưng vẫn tồn tại. Tôi muốn biết lý do tại sao điều này gây ra / dev / null không được tìm thấy trong một ls.
Gregg Leventhal

Cấp, tôi đang làm điều này trên máy Mac, vì vậy nó có thể hơi khác một chút, nhưng tôi không hy vọng tệp sẽ bị thiếu, tôi chỉ mong nó hiển thị như đã thay đổi thành tệp nguồn.
Gregg Leventhal

@GreggLeventhal có, nó phải là một thứ OSX hoặc BSD (vui lòng chỉnh sửa Q của bạn và chỉ định HĐH của bạn). Trên Linux của tôi, tôi vẫn có thể thấy /dev/null, nó chỉ trở thành tệp tôi đã di chuyển.
terdon
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.