Mẫu tên tệp Shell mở rộng thành các tệp chấm nhưng không thành `..`?


13

Gần đây tôi có một chút rủi ro gây ra bởi một mô hình vỏ mở rộng một cách bất ngờ. Tôi muốn thay đổi chủ sở hữu của một loạt các tập tin dấu chấm trong /rootthư mục, vì vậy tôi đã làm

chown -R root .*

Đương nhiên, việc .*mở rộng thành ..một chút thảm họa.

Tôi biết trong bashhành vi này có thể được thay đổi bằng cách điều chỉnh một số tùy chọn shell, nhưng với cài đặt mặc định, có bất kỳ mẫu nào sẽ mở rộng sang mọi tệp chấm trong thư mục nhưng không ...?

Câu trả lời:


20

Bash, ksh và zsh có giải pháp tốt hơn, nhưng trong câu trả lời này, tôi giả sử vỏ POSIX.

Mẫu .[!.]*phù hợp với tất cả các tệp bắt đầu bằng dấu chấm theo sau là ký tự không dấu chấm. (Lưu ý rằng [^.]được hỗ trợ bởi một số shell nhưng không phải tất cả, cú pháp di động để bổ sung bộ ký tự trong các mẫu ký tự đại diện là [!.].) Do đó, loại trừ ..., nhưng cũng có các tệp bắt đầu bằng hai dấu chấm. Mẫu ..?*xử lý các tệp bắt đầu bằng hai dấu chấm và không chỉ ...

chown -R root .[!.]* ..?*

Đây là mẫu cổ điển được đặt để khớp với tất cả các tệp:

* .[!.]* ..?*

Một hạn chế của phương pháp này là nếu một trong các mẫu không khớp với nhau, thì nó được truyền cho lệnh. Trong một tập lệnh, khi bạn muốn khớp tất cả các tệp trong một thư mục ngoại trừ ..., có một số giải pháp, tất cả chúng đều cồng kềnh:

  • Sử dụng * .*để liệt kê tất cả các mục, và loại trừ ...trong một vòng lặp. Một hoặc cả hai mẫu có thể không khớp với nhau, vì vậy vòng lặp cần kiểm tra sự tồn tại của mỗi tệp. Bạn có cơ hội để lọc các tiêu chí khác; ví dụ: xóa -hbài kiểm tra nếu bạn muốn bỏ qua các liên kết tượng trưng lơ lửng.

    for x in * .*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • Một biến thể phức tạp hơn trong đó lệnh chỉ được chạy một lần. Lưu ý rằng các tham số vị trí bị ghi đè (vỏ POSIX không có mảng); đặt điều này trong một chức năng riêng biệt nếu đây là một vấn đề.

    set --
    for x in * .[!.]* ..?*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      set -- "$@" "$x"
    done
    somecommand "$@"
  • Sử dụng * .[!.]* ..?*bộ ba. Một lần nữa, một hoặc nhiều mẫu có thể không khớp với nhau, vì vậy chúng tôi cần kiểm tra các tệp hiện có (bao gồm các liên kết tượng trưng lơ lửng).

    for x in * .[!.]* ..?*; do
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • Sử dụng * .[!.]* ..?*tryptich và chạy lệnh một lần cho mỗi mẫu nhưng chỉ khi nó khớp với thứ gì đó. Điều này chỉ chạy lệnh một lần. Lưu ý rằng các tham số vị trí bị ghi đè (vỏ POSIX không có mảng), hãy đặt nó trong một hàm riêng nếu đây là một vấn đề.

    set -- *
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- .[!.]* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- ..?* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    somecommand "$@"
  • Sử dụng find. Với GNU hoặc BSD find, việc tránh đệ quy là dễ dàng với các tùy chọn -mindepth-maxdepth. Với POSIX find, nó khó hơn một chút, nhưng có thể được thực hiện. Biểu mẫu này có ưu điểm là dễ dàng cho phép chạy lệnh một lần thay vì một lần cho mỗi tệp (nhưng điều này không được đảm bảo: nếu lệnh kết quả quá dài, lệnh sẽ được chạy trong một số đợt).

    find . -name . -o -exec somecommand {} + -o -type d -prune

6

Điều này hoạt động nếu tất cả các tên tệp chứa ít nhất ba ký tự (bao gồm cả dấu chấm):

chown -R root .??*

Đối với một giải pháp mạnh mẽ hơn, bạn có thể sử dụng find:

find . -maxdepth 1 -name '.*' -exec chown -R root {} \;
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.