a

Câu hỏi Kiểm tra xem thư mục có tồn tại trong tập lệnh shell hay không


Lệnh nào có thể được sử dụng để kiểm tra xem một thư mục có tồn tại hay không, trong một kịch bản lệnh shell?


2999
2017-09-12 20:06


gốc




Các câu trả lời:


Để kiểm tra xem một thư mục có tồn tại trong một kịch bản lệnh shell hay không, bạn có thể sử dụng như sau:

if [ -d "$DIRECTORY" ]; then
  # Control will enter here if $DIRECTORY exists.
fi

Hoặc để kiểm tra xem thư mục có tồn tại không:

if [ ! -d "$DIRECTORY" ]; then
  # Control will enter here if $DIRECTORY doesn't exist.
fi

Tuy nhiên, như Jon Ericson chỉ ra, các lệnh tiếp theo có thể không hoạt động như dự định nếu bạn không tính đến một liên kết tượng trưng đến một thư mục cũng sẽ vượt qua kiểm tra này. Ví dụ. chạy này:

ln -s "$ACTUAL_DIR" "$SYMLINK"
if [ -d "$SYMLINK" ]; then 
  rmdir "$SYMLINK" 
fi

Sẽ tạo ra thông báo lỗi:

rmdir: failed to remove `symlink': Not a directory

Vì vậy, các liên kết tượng trưng có thể phải được xử lý khác nhau, nếu các lệnh tiếp theo mong đợi các thư mục:

if [ -d "$LINK_OR_DIR" ]; then 
  if [ -L "$LINK_OR_DIR" ]; then
    # It is a symlink!
    # Symbolic link specific commands go here.
    rm "$LINK_OR_DIR"
  else
    # It's a directory!
    # Directory command goes here.
    rmdir "$LINK_OR_DIR"
  fi
fi

Lưu ý đặc biệt của các dấu ngoặc kép được sử dụng để bọc các biến, lý do cho điều này được giải thích bởi 8jean trong câu trả lời khác.

Nếu các biến chứa dấu cách hoặc các ký tự không bình thường khác, nó có thể sẽ khiến kịch bản thất bại.


4144
2017-09-12 20:07



Nếu bạn muốn chơi nó an toàn với các công cụ GNU, sử dụng -- được đánh giá cao (điểm đánh dấu cuối tùy chọn). Nếu không, nếu biến của bạn chứa thứ gì đó trông giống như một tùy chọn, tập lệnh sẽ không giống như dấu cách. - Marc Mutz - mmutz
Đối với các phiên bản hiện đại của bash, ksh, v.v ... [...] là nội dung dựng sẵn - fpmurphy1
Một điều cần lưu ý: [ ! -d "$DIRECTORY" ] sẽ đúng nếu là $DIRECTORY không tồn tại, hoặc nếu làm tồn tại nhưng không phải là một thư mục. Xem xét một cái gì đó như if [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi; điều này sẽ thất bại nếu "$DIRECTORY" là một tập tin. (Tất nhiên bạn nên kiểm tra xem liệu mkdir đã thành công; có một số lý do khiến nó có thể bị lỗi.) - Keith Thompson
Nó có thể là đáng nói đến rằng ngay sau khi kiểm tra đã được thực hiện tình hình có thể đã thay đổi đã do các quá trình khác. Trong nhiều trường hợp, tốt hơn là chỉ cần tạo hoặc sử dụng thư mục và phản ứng trên một lỗi. - Alfe
Thay vì kiểm tra cả thư mục (-d) và liên kết tượng trưng (-L), chỉ cần thêm dấu gạch chéo vào biến, if [ -d "${THING:+$THING/}" ]. Một thư mục sẽ không bận tâm thêm dấu gạch chéo. Một tệp sẽ đánh giá sai. Trống sẽ vẫn trống, vì vậy sai. Và một liên kết tượng trưng sẽ được giải quyết tới đích của nó. Tất nhiên, nó phụ thuộc vào mục tiêu của bạn. Nếu bạn muốn đi ở đó, điều này là tốt. Nếu bạn muốn xóa đi, sau đó mã trong câu trả lời này là tốt hơn. - ghoti


Hãy nhớ luôn luôn quấn các biến trong dấu ngoặc kép khi tham chiếu chúng trong một tập lệnh bash. Trẻ em ngày nay lớn lên với ý tưởng rằng chúng có thể có không gian và nhiều nhân vật hài hước khác trong tên thư mục của chúng. (Không gian! Trở lại trong những ngày của tôi, chúng tôi không có không gian ưa thích!)))

Một ngày nọ, một trong những đứa trẻ đó sẽ chạy kịch bản của bạn $DIRECTORY đặt thành "My M0viez" và kịch bản của bạn sẽ nổ tung. Bạn không muốn điều đó. Vì vậy, sử dụng này.

if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists, even if it contains spaces
fi

454
2017-09-15 22:00



Một lý do khác để sử dụng dấu ngoặc kép là trong trường hợp $ DIRECTORY không được đặt cho một số lý do. - Jon Ericson♦
"luôn luôn quấn các biến trong dấu nháy kép ... trong một tập lệnh bash." Đối với bash, không cần thiết về mặt kỹ thuật khi sử dụng [[...]]; xem tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS (lưu ý: không chia tách từ): "Không mở rộng tên tập tin hoặc tách từ diễn ra giữa [[và]], nhưng có sự mở rộng tham số và thay thế lệnh." - michael
Thư mục trên Unix / Linux không được có bất kỳ khoảng trắng nào và các tập lệnh sau đó sẽ không được điều chỉnh cho phù hợp. Nó đủ tệ để Windows hỗ trợ nó, với mọi hậu quả đối với kịch bản Windows, nhưng làm ơn, vì tình yêu của bất cứ điều gì, không cần phải đưa ra những yêu cầu không cần thiết. - tvCa
@tvCa Tôi thấy rằng người dùng thường thích được phép linh hoạt hơn trong tên thư mục của họ thay vì bị buộc phải làm mọi thứ dễ dàng hơn cho nhà phát triển. (Thực tế, khi giao dịch với tên tệp dài, tôi thấy những cái không có dấu cách để làm đau đớn khi giết chết gói chữ mặc dù bản thân tôi đã chịu đựng trong quá khứ không tính đến đường dẫn có khoảng trống trong các tập lệnh và chương trình.) - JAB
Ha. Dấu cách chỉ là các ký tự không có glyph. Dù sao, bạn có thể thoát chúng bằng dấu gạch chéo ngược. - uchuugaka


Lưu ý -d thử nghiệm có thể tạo ra một số kết quả đáng ngạc nhiên:

$ ln -s tmp/ t
$ if [ -d t ]; then rmdir t; fi
rmdir: directory "t": Path component not a directory

Tệp dưới: "Khi nào một thư mục không phải là thư mục?" Câu trả lời: "Khi đó là một liên kết tượng trưng đến một thư mục." Một bài kiểm tra kỹ lưỡng hơn:

if [ -d t ]; then 
   if [ -L t ]; then 
      rm t
   else 
      rmdir t
   fi
fi

Bạn có thể tìm thêm thông tin trong hướng dẫn sử dụng Bash trên Các biểu thức điều kiện Bash và [ lệnh nội trang và [[ hợp đồng commmand.


204
2017-09-12 20:26



hoặc, giả sử nó chỉ cần thiết để làm việc trên các thư mục (và các liên kết có thể được bỏ qua) => if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi ... hoặc, cho một lệnh hoạt động trên cả hai liên kết và thư mục: rm -r tmpdir - michael


Tôi tìm thấy khung đôi phiên bản của test làm cho việc viết các bài kiểm tra logic tự nhiên hơn:

if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
    echo "It's a bona-fide directory"
fi

198
2017-09-12 21:33



cho if [[ -d "$TARFILE" ]] Tôi nhận được [[: không tìm thấy - TheVillageIdiot
ditto [[: không tìm thấy - Hedgehog
@ TheVillageIdiot và @Hedgehog, bạn có sử dụng bash shell không? Khung đôi không được hỗ trợ phổ biến. Đây là một câu trả lời SO vào thời điểm đó: stackoverflow.com/questions/669452/… - yukondude
Và trong tro Busybox với các tùy chọn biên dịch mặc định [[ ]] được hỗ trợ, nhưng không thực tế cung cấp bất kỳ chức năng nào khác cho [ ]. Nếu tính di động là một mối quan tâm, hãy gắn bó với [ ] và sử dụng các cách giải quyết cần thiết. - dubiousjim
... nếu sử dụng các cấu trúc bash trong một kịch bản lệnh shell, dòng đầu tiên của tập lệnh phải là: #! / bin / bash (và không phải #! / bin / sh, ksh, v.v.) - michael


Dạng ngắn hơn:

[ -d "$DIR" ] && echo "Yes"

125
2017-09-12 21:08



Điều này làm việc như thế này: if $dir is a dir, then echo "yes"? Một chút giải thích sẽ giúp :) - Martijn
cmd && other là một cách viết tắt phổ biến cho if cmd; then other; fi - điều này làm việc với hầu hết các ngôn ngữ lập trình hỗ trợ logic Boolean, và được gọi là đánh giá ngắn mạch. - tripleee
Hành vi không giống nhau theo set -e (mà là một shell lập trình thực hành tốt nhất). - dolmen


Để kiểm tra xem một thư mục có tồn tại hay không, bạn có thể sử dụng cấu trúc đơn giản nếu như sau:

if [ -d directory/path to a directory ] ; then
#Things to do

else #if needed #also: elif [new condition] 
# things to do
fi

Bạn có thể làm điều đó cũng tiêu cực

if [ ! -d directory/path to a directory ] ; then
# things to do when not an existing directory

chú thích: Hãy cẩn thận, để trống các khoảng trống ở cả hai bên của nẹp mở và đóng.

Với cùng cú pháp bạn có thể sử dụng:

-e: any kind of archive 

-f: file 

-h: symbolic link 

-r: readable file 

-w: writable file 

-x: executable file 

-s: file size greater than zero 

119
2018-04-08 02:50





if [ -d "$DIRECTORY" ]; then  
    # Here if $DIRECTORY exists  
fi

94
2018-04-15 08:07





Bạn có thể dùng test -d (xem man test).

-d file       Đúng nếu tập tin tồn tại và là một thư mục.

Ví dụ:

test -d "/etc" && echo Exists || echo Does not exist

Lưu ý: The test lệnh giống như biểu thức điều kiện [ (xem: man [), do đó, nó di động trên các tập lệnh shell.

[ - Đây là một từ đồng nghĩa cho test được xây dựng, nhưng đối số cuối cùng phải là một chữ ], để khớp với phần mở đầu [.

Để biết các tùy chọn có thể hoặc trợ giúp thêm, hãy kiểm tra:

  • help [
  • help test
  • man test hoặc là man [

74
2017-09-12 21:25





Hoặc cho một cái gì đó hoàn toàn vô dụng:

[ -d . ] || echo "No"

55
2017-08-17 14:02



Nó sẽ không bao giờ in "Không". Thư mục hiện tại luôn tồn tại, trừ khi bị xóa bởi một chuỗi khác hoặc các cách khác. - Jahid
Mẫu hoàn hảo :) cho rằng cách "duy nhất" là một số câu trả lời so với câu trả lời được chấp nhận - Sergey Sargsyan
Tại sao điều này đã được upvoted rất nhiều lần? Nó không trả lời câu hỏi. - codeforester


Đây là một thành ngữ rất thực dụng:

(cd $dir) || return # is this a directory,
                    # and do we have access?

Tôi thường quấn nó trong một hàm:

can_use_as_dir() { 
    (cd ${1:?pathname expected}) || return
}

Hoặc là:

assert_dir_access() { 
    (cd ${1:?pathname expected}) || exit
}

Điều tốt đẹp về cách tiếp cận này là tôi không phải nghĩ đến một thông báo lỗi tốt.

cd sẽ cho tôi một thông điệp một dòng tiêu chuẩn để stderr rồi. Nó cũng sẽ cung cấp thêm thông tin hơn tôi sẽ có thể cung cấp. Bằng cách thực hiện cd bên trong một vỏ bọc ( ... ), lệnh không ảnh hưởng đến thư mục hiện tại của người gọi. Nếu thư mục tồn tại, subshell này và hàm chỉ là một no-op.

Tiếp theo là đối số mà chúng tôi chuyển đến cd: ${1:?pathname expected}. Đây là dạng thay thế tham số phức tạp hơn, được giải thích chi tiết hơn bên dưới.

Tl; dr: Nếu chuỗi được truyền vào hàm này trống, chúng ta lại thoát khỏi subshell ( ... ) và trở về từ hàm với thông báo lỗi đã cho.


Trích dẫn từ ksh93 trang người đàn ông:

${parameter:?word}

Nếu parameter  được thiết lập và không rỗng sau đó thay thế giá trị của nó;   nếu không, in word và thoát khỏi trình bao (nếu không tương tác).   Nếu word được bỏ qua sau đó một thông điệp tiêu chuẩn được in.

Nếu dấu hai chấm : được bỏ qua từ các biểu thức trên, sau đó   shell chỉ kiểm tra xem tham số có được đặt hay không.

Phrasing ở đây là đặc biệt với tài liệu shell, như word có thể tham khảo cho bất kỳ chuỗi hợp lý nào, kể cả khoảng trắng.

Trong trường hợp đặc biệt này, tôi biết rằng thông báo lỗi chuẩn 1: parameter not set không đủ, vì vậy tôi phóng to loại giá trị mà chúng tôi mong đợi ở đây - pathname của một thư mục.

Một lưu ý philippical: Vỏ không phải là ngôn ngữ hướng đối tượng, vì vậy thông báo nói pathname, không phải directory. Ở cấp độ này, tôi muốn giữ nó đơn giản - các đối số cho một hàm chỉ là các chuỗi.


46
2017-08-09 21:43



Thao tác này không chỉ kiểm tra tính tồn tại: Kiểm tra khả năng truy cập này ở cấp người dùng của bạn. SO câu hỏi đứng cho sự tồn tại chỉ có. Câu trả lời đúng là test -d như @Grundlefleck đã giải thích. - F. Hauri
@ F.Hauri - Anh ta không yêu cầu thêm bất cứ điều gì, đó là sự thật. Tuy nhiên, tôi đã thấy rằng tôi thường cần phải biết nhiều hơn thế. - Henk Langeveld
Và nó không bao giờ xảy ra với tôi rằng không có thử nghiệm có thể được kết luận, trừ khi nó chạy như root. test -d /unreadable/exists sẽ thất bại, ngay cả khi đối số tồn tại. - Henk Langeveld