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 tập lệnh shell Bash?
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 tập lệnh shell Bash?
Câu trả lời:
Để kiểm tra xem một thư mục có tồn tại trong tập 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 một thư mục không tồn tại:
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 việc 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 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 về 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 một câu trả lời khác .
Nếu các biến chứa khoảng trắng hoặc các ký tự bất thường khác, nó có thể sẽ khiến tập lệnh bị lỗi.
[ ! -d "$DIRECTORY" ]
sẽ là sự thật, hoặc nếu $DIRECTORY
không tồn tại, hoặc nếu không tồn tại nhưng không phải là một thư mục. Hãy 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 dù mkdir
thành công hay không; có một số lý do khiến nó có thể thất bại.)
-d
) và symlink ( -L
), việc thêm một dấu gạch chéo vào biến, sẽ dễ dàng hơn if [ -d "${THING:+$THING/}" ]
. Một thư mục sẽ không quan tâm đến dấu gạch chéo. Một tập tin sẽ đánh giá thành sai. Trống sẽ vẫn trống, rất sai. Và một symlink sẽ được giải quyết đến đí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 nó , thì mã trong câu trả lời này là tốt hơn.
Hãy nhớ luôn luôn bọc các biến trong dấu ngoặc kép khi tham chiếu chúng trong 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à rất nhiều nhân vật ngộ nghĩnh khác trong tên thư mục của chúng. (Không gian! Quay lại thời của tôi, chúng tôi đã không có không gian ưa thích !;))
Một ngày nào đó, một trong những đứa trẻ đó sẽ chạy tập lệnh của bạn với $DIRECTORY
cài đặt "My M0viez"
và tập lệnh 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
Lưu ý kiểm tra -d 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 tin bên dưới: "Khi nào một thư mục không phải là một 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 một chút:
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 Bash về các biểu thức điều kiện Bash và [
lệnh dựng sẵn và dấu [[
phẩy ghép .
if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi
... hoặc, đối với một lệnh hoạt động trên cả hai liên kết & thư mục:rm -r tmpdir
Tôi thấy phiên bản khung đôitest
giúp việc viết các bài kiểm tra logic trở nên tự nhiên hơn:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
if [[ -d "$TARFILE" ]]
tôi nhận được [[: không tìm thấy
[[ ]]
được hỗ trợ, nhưng trên thực tế không cung cấp bất kỳ chức năng nào khác [ ]
. Nếu tính di động là một mối quan tâm, hãy gắn bó [ ]
và sử dụng các cách giải quyết cần thiết.
Mẫu ngắn hơn:
[ -d "$DIR" ] && echo "Yes"
if $dir is a dir, then echo "yes"
không? Một chút giải thích sẽ giúp :)
cmd && other
là một cách viết tắt phổ biến cho if cmd; then other; fi
- điều này hoạt động 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 .
set -e
(đó là một thực hành tốt nhất lập trình shell ).
[ -d "$DIR" ]
được kiểm tra (theo sau && echo Yes
), vì vậy tôi tin rằng set -e
không có sự khác biệt nào đối với hành vi tập lệnh (nghĩa là nếu thử nghiệm thất bại, tập lệnh tiếp tục bình thường).
Để kiểm tra xem một thư mục có tồn tại không, bạn có thể sử dụng một if
cấu trúc đơn giản như thế này:
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ũng có thể làm điều đó trong phủ định:
if [ ! -d directory/path to a directory ] ; then
# Things to do when not an existing directory
Lưu ý : Cẩn thận. Để lại các khoảng trống ở hai bên của cả hai dấu ngoặc mở và đóng.
Với cùng một 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
Một tập lệnh đơn giản để kiểm tra xem một thư mục hoặc tập tin có hay không:
if [ -d /home/ram/dir ] # For file "if [-f /home/rama/file]"
then
echo "dir present"
else
echo "dir not present"
fi
Một tập lệnh đơn giản để kiểm tra xem thư mục có mặt hay không:
mkdir tempdir # If you want to check file use touch instead of mkdir
ret=$?
if [ "$ret" == "0" ]
then
echo "dir present"
else
echo "dir not present"
fi
Các kịch bản trên sẽ kiểm tra xem thư mục có mặt hay không
$?
nếu lệnh cuối cùng thành công, nó sẽ trả về "0", nếu không thì giá trị khác không. Giả sử tempdir
đã có mặt. Sau đó mkdir tempdir
sẽ đưa ra một lỗi như dưới đây:
mkdir: không thể tạo thư mục 'tempdir': Tệp tồn tại
Bạn có thể sử 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 ý: test
Lệnh này giống như biểu thức điều kiện [
(xem man [
:), vì vậy nó có thể di chuyển trên các tập lệnh shell.
[
- Đây là một từ đồng nghĩa vớitest
nội dung, nhưng đối số cuối cùng phải, theo nghĩa đen]
, để phù hợp với phần mở đầu[
.
Đối với 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 [
Hoặc cho một cái gì đó hoàn toàn vô dụng:
[ -d . ] || echo "No"
Đâ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 bọc nó trong một chức năng:
can_use_as_dir() {
(cd ${1:?pathname expected}) || return
}
Hoặc là:
assert_dir_access() {
(cd ${1:?pathname expected}) || exit
}
Điều hay ho 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ẽ cung cấp cho tôi một thông báo một dòng tiêu chuẩn cho lỗi tiêu chuẩn . Nó cũng sẽ cung cấp nhiều 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 lớp con ( ... )
, 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, lớp con này và hàm chỉ là một no-op.
Tiếp theo là đối số mà chúng ta chuyển đến cd
: ${1:?pathname expected}
. Đây là một hình thức thay thế tham số phức tạp hơn được giải thích chi tiết hơn dưới đây.
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 lớp con ( ... )
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 đặt và không null thì thay thế giá trị của nó; mặt khác, inword
và thoát khỏi vỏ (nếu không tương tác). Nếuword
được bỏ qua thì một thông điệp tiêu chuẩn được in.
và
Nếu dấu hai chấm
:
được bỏ qua trong các biểu thức trên, thì shell chỉ kiểm tra xem tham số có được đặt hay không.
Phrasing ở đây là đặc thù của tài liệu shell, vì word
có thể đề cập đến bất kỳ chuỗi hợp lý nào, bao gồm cả khoảng trắng.
Trong trường hợp cụ thể này, tôi biết rằng thông báo lỗi tiêu chuẩn 1: parameter not set
là 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 ghi chú triết học:
Shell không phải là một ngôn ngữ hướng đối tượng, vì vậy thông báo nói pathname
, không directory
. Ở cấp độ này, tôi muốn giữ cho nó đơn giản - các đối số cho hàm chỉ là các chuỗi.
test -d
như @Grundlefleck giải thích.
test -d /unreadable/exists
sẽ thất bại, ngay cả khi đối số tồn tại.
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
fi
Các mã trên kiểm tra nếu thư mục tồn tại và nếu nó có thể ghi.
DIRECTORY=/tmp
if [ -d "$DIRECTORY" ]; then
echo "Exists"
fi
space
sau [
-> [`` -d . tôi đã gặp lỗi vì thiếu không gian
Nhập mã này vào dấu nhắc Bash:
if [ -d "$DIRECTORY" ]; then
# If true this block of code will execute
fi
find
Kiểm tra sự tồn tại của thư mục trong các thư mục con:
found=`find -type d -name "myDirectory"`
if [ -n "$found"]
then
# The variable 'found' contains the full path where "myDirectory" is.
# It may contain several lines if there are several folders named "myDirectory".
fi
Kiểm tra sự tồn tại của một hoặc một số thư mục dựa trên một mẫu trong thư mục hiện tại:
found=`find -maxdepth 1 -type d -name "my*"`
if [ -n "$found"]
then
# The variable 'found' contains the full path where folders "my*" have been found.
fi
Cả hai kết hợp. Trong ví dụ sau, nó kiểm tra sự tồn tại của thư mục trong thư mục hiện tại:
found=`find -maxdepth 1 -type d -name "myDirectory"`
if [ -n "$found"]
then
# The variable 'found' is not empty => "myDirectory"` exists.
fi
find -maxdepth 1 -type d -name 'pattern'
. Bạn có phiền nếu tôi nối vào câu trả lời của bạn không? Chúc mừng;)
Trên thực tế, bạn nên sử dụng một số công cụ để có được cách tiếp cận chống đạn:
DIR_PATH=`readlink -f "${the_stuff_you_test}"` # Get rid of symlinks and get abs path
if [[ -d "${DIR_PATH}" ]] ; Then # Now you're testing
echo "It's a dir";
fi
Không cần phải lo lắng về không gian và các ký tự đặc biệt miễn là bạn sử dụng "${}"
.
Lưu ý rằng [[]]
nó không phải là di động như []
, nhưng vì hầu hết mọi người làm việc với các phiên bản hiện đại của Bash (vì xét cho cùng, hầu hết mọi người thậm chí không làm việc với dòng lệnh :-p), lợi ích lớn hơn rắc rối.
Bạn đã xem xét chỉ làm bất cứ điều gì bạn muốn làm trong if
hơn là tìm kiếm trước khi bạn nhảy?
Tức là, nếu bạn muốn kiểm tra sự tồn tại của một thư mục trước khi bạn nhập nó, hãy thử làm điều này:
if pushd /path/you/want/to/enter; then
# Commands you want to run in this directory
popd
fi
Nếu đường dẫn bạn đưa ra để pushd
tồn tại, bạn sẽ nhập nó và nó sẽ thoát theo 0
, có nghĩa là then
phần của câu lệnh sẽ thực thi. Nếu nó không tồn tại, sẽ không có gì xảy ra (ngoài một số đầu ra nói rằng thư mục không tồn tại, đây có thể là một tác dụng phụ hữu ích để gỡ lỗi).
Có vẻ tốt hơn thế này, đòi hỏi phải lặp lại chính mình:
if [ -d /path/you/want/to/enter ]; then
pushd /path/you/want/to/enter
# Commands you want to run in this directory
popd
fi
Điều tương tự cũng làm việc với cd
, mv
, rm
, vv ... nếu bạn thử chúng trên các tập tin không tồn tại, họ sẽ thoát ra với một lỗi và in một thông báo nói rằng nó không tồn tại, và bạnthen
khối sẽ bị bỏ qua. Nếu bạn thử chúng trên các tệp tồn tại, lệnh sẽ thực thi và thoát với trạng thái 0
, cho phép then
khối của bạn thực thi.
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
NB: Trích dẫn các biến là một thực hành tốt.
Giải trình:
-d
: kiểm tra xem đó có phải là một thư mục không-L
: kiểm tra xem đó có phải là một liên kết tượng trưng khôngĐể kiểm tra nhiều thư mục, hãy sử dụng mã này:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
Kiểm tra nếu thư mục tồn tại, khác làm cho một:
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
mkdir -p "$DIRECTORY"
cho cùng một hiệu ứng.
[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
Câu trả lời này được gói gọn như một kịch bản shell
$ is_dir ~
YES
$ is_dir /tmp
YES
$ is_dir ~/bin
YES
$ mkdir '/tmp/test me'
$ is_dir '/tmp/test me'
YES
$ is_dir /asdf/asdf
NO
# Example of calling it in another script
DIR=~/mydata
if [ $(is_dir $DIR) == "NO" ]
then
echo "Folder doesnt exist: $DIR";
exit;
fi
function show_help()
{
IT=$(CAT <<EOF
usage: DIR
output: YES or NO, depending on whether or not the directory exists.
)
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ -z "$1" ]
then
show_help
fi
DIR=$1
if [ -d $DIR ]; then
echo "YES";
exit;
fi
echo "NO";
Sử dụng -e
kiểm tra sẽ kiểm tra các tập tin và điều này bao gồm các thư mục.
if [ -e ${FILE_PATH_AND_NAME} ]
then
echo "The file or directory exists."
fi
Theo nhận xét của Jonathan :
Nếu bạn muốn tạo thư mục và nó chưa tồn tại, thì kỹ thuật đơn giản nhất là sử dụng mkdir -p
để tạo thư mục - và bất kỳ thư mục bị thiếu nào trên đường dẫn - và không thất bại nếu thư mục đã tồn tại, vì vậy bạn có thể làm tất cả cùng một lúc với:
mkdir -p /some/directory/you/want/to/exist || exit 1
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists
fi
Điều này không hoàn toàn đúng...
Nếu bạn muốn vào thư mục đó, bạn cũng cần có quyền thực thi trên thư mục. Có lẽ bạn cần phải có quyền viết là tốt.
Vì thế:
if [ -d "$DIRECTORY" ] && [ -x "$DIRECTORY" ] ; then
# ... to go to that directory (even if DIRECTORY is a link)
cd $DIRECTORY
pwd
fi
if [ -d "$DIRECTORY" ] && [ -w "$DIRECTORY" ] ; then
# ... to go to that directory and write something there (even if DIRECTORY is a link)
cd $DIRECTORY
touch foobar
fi
Sử dụng file
chương trình. Xem xét tất cả các thư mục cũng là các tệp trong Linux, ban hành lệnh sau sẽ đủ:
file $directory_name
Kiểm tra tệp không tồn tại: file blah
Đầu ra: cannot open 'blah' (No such file or directory)
Kiểm tra một thư mục hiện có: file bluh
Đầu ra: bluh: directory
Các ls
lệnh kết hợp với -l
(dài niêm yết) trả về tùy chọn các thuộc tính thông tin về các tập tin và thư mục.
Cụ thể, ký tự đầu tiên của ls -l
đầu ra, nó thường là a d
hoặc -
dấu gạch ngang. Trong trường hợp một d
trong những người được liệt kê là một thư mục chắc chắn.
Lệnh sau chỉ trong một dòng sẽ cho bạn biết nếu ISDIR
biến đã cho có chứa đường dẫn đến thư mục hay không:
[[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directory"
Cách sử dụng thực tế:
[claudio@nowhere ~]$ ISDIR="$HOME/Music"
[claudio@nowhere ~]$ ls -ld "$ISDIR"
drwxr-xr-x. 2 claudio claudio 4096 Aug 23 00:02 /home/claudio/Music
[claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directory"
YES, /home/claudio/Music is a directory.
[claudio@nowhere ~]$ touch "empty file.txt"
[claudio@nowhere ~]$ ISDIR="$HOME/empty file.txt"
[claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directoy"
Sorry, /home/claudio/empty file.txt is not a directory
file="foo"
if [[ -e "$file" ]]; then echo "File Exists"; fi;
Nếu bạn muốn kiểm tra xem một thư mục có tồn tại hay không, bất kể đó là thư mục thực hay liên kết tượng trưng, hãy sử dụng:
ls $DIR
if [ $? != 0 ]; then
echo "Directory $DIR already exists!"
exit 1;
fi
echo "Directory $DIR does not exist..."
Giải thích: Lệnh "ls" đưa ra lỗi "ls: / x: Không có tệp hoặc thư mục như vậy" nếu thư mục hoặc symlink không tồn tại và cũng đặt mã trả về mà bạn có thể truy xuất thông qua "$?", Không -null (thường là "1"). Hãy chắc chắn rằng bạn kiểm tra mã trả lại trực tiếp sau khi gọi "ls".
if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; fi
(1)
[ -d Piyush_Drv1 ] && echo ""Exists"" || echo "Not Exists"
(2)
[ `find . -type d -name Piyush_Drv1 -print | wc -l` -eq 1 ] && echo Exists || echo "Not Exists"
(3)
[[ -d run_dir && ! -L run_dir ]] && echo Exists || echo "Not Exists"
Nếu một vấn đề được tìm thấy với một trong những cách tiếp cận được cung cấp ở trên:
Với ls
mệnh lệnh; các trường hợp khi một thư mục không tồn tại - một thông báo lỗi được hiển thị
[[ `ls -ld SAMPLE_DIR| grep ^d | wc -l` -eq 1 ]] && echo exists || not exists
-ksh: not: not find [Không có tập tin hoặc thư mục như vậy]
Có những giải pháp tuyệt vời ngoài kia, nhưng cuối cùng mọi kịch bản sẽ thất bại nếu bạn không ở đúng thư mục. Mã như thế này:
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
sẽ chỉ thực hiện thành công nếu tại thời điểm thực thi bạn đang ở trong một thư mục có thư mục con mà bạn tình cờ kiểm tra.
Tôi hiểu câu hỏi ban đầu như thế này: để xác minh xem một thư mục có tồn tại không phân biệt vị trí của người dùng trong hệ thống tệp. Vì vậy, sử dụng lệnh 'find' có thể thực hiện thủ thuật:
dir=" "
echo "Input directory name to search for:"
read dir
find $HOME -name $dir -type d
Giải pháp này rất tốt vì nó cho phép sử dụng ký tự đại diện, một tính năng hữu ích khi tìm kiếm tệp / thư mục. Vấn đề duy nhất là, nếu thư mục được tìm kiếm không tồn tại, lệnh 'find' sẽ không in gì cho đầu ra tiêu chuẩn (không phải là một giải pháp tao nhã theo sở thích của tôi) và dù sao cũng sẽ có một lối thoát bằng không. Có lẽ ai đó có thể cải thiện điều này.
locate
nhưng không tốt cho bất kỳ thứ gì khác ...
--
rất được khuyến khích (điểm đánh dấu kết thúc tùy chọn). Mặt khác, 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ẽ thất bại giống như với khoảng trắng.