Làm thế nào tôi có thể tìm hiểu xem một liên kết tương đối có nội bộ với một cây con nhất định hay không?


7

Tôi muốn kiểm tra nếu một điểm liên kết tương đối trong phạm vi của một thư mục nhất định.

Ví dụ này sẽ mang lại falsevì nó trỏ ra ngoài foothư mục:
/foo>readlink bar
../fie.txt

Trong khi ví dụ này sẽ mang lại true:
/foo>readlink bar
fum/fie.txt

Có một tiện ích hiện có nào tôi có thể tận dụng hay tôi sẽ phải mã hóa nó từ đầu? Tôi đang sử dụng bash.


Điều gì nếu fie.txthoặc fumchính nó là một liên kết tượng trưng bên ngoài foo?
Stéphane Chazelas

Bạn sẽ luôn chạy nó từ /foohoặc bạn cần để có thể vượt qua các thư mục tùy ý? Ý tôi là, câu hỏi luôn luôn tôn trọng ./hay không?
terdon

@StephaneChazelas Vâng, đó là một vấn đề mà tôi chọn bỏ qua, ít nhất là như vậy. Tôi nghĩ rằng tôi sẽ mở rộng liên kết bằng cách sử dụng readlink -f và xem các tiền tố có khớp không. Nhưng tôi sẽ bỏ qua các trường hợp góc điên vì chúng không tồn tại trong môi trường của chúng ta.
Fylke

@terdon Không, nó nên chấp nhận các thư mục tùy ý.
Fylke

Có một cái nhìn vào symlinks , nó có thể giúp đỡ.
Phục hồi Monica - M. Schröder

Câu trả lời:


5

Tôi không nghĩ có một tiện ích như vậy. Với GNU readlink, bạn có thể làm một cái gì đó như:

is_in() (
  needle=$(readlink -ve -- "$1" && echo .) || exit
  haystack=$(readlink -ve -- "$2" && echo .) || exit
  needle=${needle%??} haystack=${haystack%??}
  haystack=${haystack%/} needle=${needle%/}
  case $needle in
    ("$haystack" | "$haystack"/*) true;;
    (*) false;;
  esac
)

Điều đó giải quyết tất cả các liên kết tượng trưng để kết thúc với một đường dẫn tuyệt đối chính tắc cho cả kim và haystack.

Giải trình

  • Chúng ta có được đường dẫn tuyệt đối chính tắc của cả kimcỏ khô . Chúng tôi sử dụng -ethay vì -fnhư chúng tôi muốn đảm bảo các tập tin tồn tại. Các -vtùy chọn đưa ra một thông báo lỗi nếu các tập tin không thể truy cập.
  • Như mọi khi, --nên được sử dụng để đánh dấu sự kết thúc của các tùy chọn và trích dẫn vì chúng tôi không muốn gọi toán tử split + global ở đây.
  • Thay thế lệnh trong các shell giống như Bourne có một lỗi không phù hợp ở chỗ nó loại bỏ tất cả các ký tự dòng mới khỏi đầu ra của một lệnh, không chỉ là một lệnh được thêm bởi các lệnh để kết thúc dòng cuối cùng. Điều đó có nghĩa là đối với một tệp như thế /foo<LF><LF>, $(readlink -ve -- "$1")sẽ trả về /foo. Các công việc xung quanh chung cho rằng là để nối thêm một nhân vật phi LF (ở đây .) và dải đó và nhân vật LF phụ thêm bởi readlinkvới var=${var%??}(loại bỏ hai ký tự cuối cùng).
  • Cây kim được coi là nằm trong đống cỏ khô nếu đó là đống cỏ khô hoặc nếu đó là đống cỏ khô / thứ gì đó. Tuy nhiên, điều đó sẽ không hoạt động nếu haystack là /( /etcthay vào đó là không //something). /thường cần được xử lý đặc biệt bởi vì trong khi //xxcó cùng số lượng dấu gạch chéo, thì một mức này cao hơn mức khác.

    Một cách để giải quyết nó là để thay thế /với chuỗi rỗng mà được thực hiện với var=${var%/}(con đường duy nhất kết thúc với /đó readlink -e/, vì vậy việc xoá dấu /được thay đổi /để chuỗi rỗng).

Để chuẩn hóa đường dẫn tệp, bạn có thể sử dụng chức năng trợ giúp.

canonicalize_path() {
  # canonicalize paths stored in supplied variables. `/` is returned as 
  # the empty string.
  for _var do
    eval '
      '"$_var"'=$(readlink -ve -- "${'"$_var"'}" && echo .) &&
      '"$_var"'=${'"$_var"'%??} &&
      '"$_var"'=${'"$_var"'%/}' || return
  done
}

is_in() (
  needle=$1 haystack=$2
  canonicalize_path needle haystack || exit
  case $needle in
    ("$haystack" | "$haystack"/*) true;;
    (*) false;;
  esac
)

Tôi thấy nghiên cứu bài này rất hướng dẫn. Tôi có thể hỏi bạn một vài câu hỏi không? Có bất kỳ ý nghĩa trong thực tế là trong needle=${needle%??} haystack=${haystack%??}các needlebiến được xử lý đầu tiên, trong khi đó ở dòng tiếp theo đó là cách khác xung quanh? Ngoài ra, tại sao các returntuyên bố của bạn không trả về một giá trị khác không (để chỉ ra lỗi)? Điều cuối cùng: sẽ có ý nghĩa khi đưa ra toàn bộ biến đổi (lời gọi đến readlink, cộng với hai lần cắt hậu tố) thành một _canonicalize_pathhàm trợ giúp riêng biệt ?
kjo

1
@kjo, 1) không có ý nghĩa 2) returntrả về theo mặc định với trạng thái của lệnh cuối cùng. Với || return, điều đó cho phép trả về trạng thái như được cung cấp bởi ứng dụng bị lỗi. 3) chắc chắn, nhưng chức năng kết quả có thể sẽ không phải là một cảnh dễ chịu. Tôi sẽ thêm một ví dụ.
Stéphane Chazelas

Cảm ơn! Tôi hiểu ý bạn là gì! Không phải là một cảnh dễ chịu chút nào. Lập trình Shell phải là loại lập trình khó nhất mà tôi biết ...
kjo 22/2/2016

0

Tôi đã giải quyết vấn đề như thế này:

echo $abs_link_target | grep -qe "^$containing_dir"

Các $abs_link_targetbiến chứa đường dẫn Absolut với mục tiêu liên kết tượng trưng (mở rộng thông qua readlink -f). Sau đó tôi kiểm tra xem điểm bắt đầu của đường dẫn đích có khớp với điểm bắt đầu của$containing_dir


Nó sẽ nói rằng / foobar nằm trong / foo
Stéphane Chazelas

Nó sẽ nói rằng / abc / d nằm trong / ab ( $containing_dirđược coi là một biểu thức chính quy)
Stéphane Chazelas

Nó sẽ nói rằng / abc nằm trong /foo<LF>/abc(các dòng của chuỗi mẫu được coi là các mẫu khác nhau để khớp)
Stéphane Chazelas

Nó sẽ nói rằng đó /foo<LF>/abc/abc( grepkhớp trên mỗi dòng của đầu vào, không phải toàn bộ đầu vào nên thường không thể được sử dụng để khớp với tên tệp).
Stéphane Chazelas

Tùy thuộc vào việc echotriển khai và / hoặc môi trường, bạn sẽ không gặp vấn đề với tên tệp chứa dấu gạch chéo ngược echođể xử lý dữ liệu tùy ý
Stéphane Chazelas

0

grep -q "^/foo/bar/" <<< "$(readlink -f "anyfile.ext")"


1
Giả sử mục tiêu anyfile.exttồn tại và có thể truy cập (nếu không, readlink -fngược lại readlink -ecó thể không cung cấp cho bạn đường dẫn chính xác) và đường dẫn kết quả không chứa các ký tự dòng mới (giả sử zsh hoặc bash4 hoặc ksh93m + trở lên). Lưu ý rằng nếu anyfile.exttrỏ vào /foo/barchính nó, nó sẽ nói rằng nó không nằm trong.
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.