Để xử lý các tên tệp tùy ý (bao gồm cả các tên chứa ký tự dòng mới), mẹo thông thường là tìm các tệp bên trong .//.
thay vì .
. Bởi vì //
thông thường không thể xảy ra trong khi di chuyển ngang qua cây thư mục, bạn chắc chắn rằng //
tín hiệu bắt đầu tên tệp mới trong đầu ra find
(hoặc ở đây lsattr -R
).
lsattr -R .//. | awk '
function process() {
i = index(record, " ")
if (i && index(substr(record,1,i), "i"))
print substr(record, i+4)
}
{
if (/\/\//) {
process()
record=$0
} else {
record = record "\n" $0
}
}
END{process()}'
Lưu ý rằng đầu ra vẫn sẽ được phân tách dòng mới. Nếu bạn cần xử lý hậu kỳ, bạn sẽ phải điều chỉnh nó. Chẳng hạn, bạn có thể thêm một -v ORS='\0'
để có thể cung cấp nó cho GNU xargs -r0
.
Cũng lưu ý rằng lsattr -R
(ít nhất 1.42.13) không thể báo cáo cờ của các tệp có đường dẫn lớn hơn PATH_MAX (thường là 4096), vì vậy ai đó có thể ẩn tệp bất biến đó bằng cách di chuyển thư mục mẹ của nó (hoặc bất kỳ thành phần đường dẫn nào dẫn đến nó, ngoại trừ chính nó là bất biến) vào một thư mục rất sâu.
Một công việc xung quanh sẽ được sử dụng find
với -execdir
:
find . -execdir sh -c '
a=$(lsattr -d "$1") &&
case ${a%% *} in
(*i*) ;;
(*) false
esac' sh {} \; -print0
Bây giờ, với -print0
, đó là hậu xử lý, nhưng nếu bạn có ý định làm bất cứ điều gì với các đường dẫn đó, hãy lưu ý rằng bất kỳ cuộc gọi hệ thống nào trên các đường dẫn tệp lớn hơn PATH_MAX vẫn sẽ bị lỗi và các thành phần thư mục có thể được đổi tên trong khoảng.
Nếu chúng ta nhận được một báo cáo đáng tin cậy về cây thư mục có khả năng ghi được bởi những người khác, thì có một vài vấn đề cố hữu đối với lsattr
chính lệnh mà chúng ta cần đề cập:
- cách
lsattr -R .
đi qua cây thư mục, nó phải tuân theo các điều kiện chủng tộc. Người ta có thể làm cho nó xuống các thư mục bên ngoài cây thư mục được định tuyến .
bằng cách thay thế một số thư mục bằng symlink vào đúng thời điểm.
- thậm chí
lsattr -d file
có một điều kiện chủng tộc. Những thuộc tính này chỉ áp dụng cho các tập tin hoặc thư mục thông thường. Vì vậy, lsattr
không một lstat()
đầu tiên để kiểm tra xem các tập tin là trong những loại phải và sau đó không open()
tiếp theo ioctl()
để lấy các thuộc tính. Nhưng nó gọi open()
mà không có O_NOFOLLOW
(cũng không phải O_NOCTTY). Ai đó có thể thay thế file
bằng một liên kết tượng trưng /dev/watchdog
chẳng hạn giữa lstat()
và open()
và khiến hệ thống khởi động lại. Nó nên làm open(O_PATH|O_NOFOLLOW)
theo sau fstat()
, openat()
và ioctl()
ở đây để tránh các điều kiện cuộc đua.