Câu trả lời:
Bạn có thể chỉ định một dấu gạch chéo ở cuối để chỉ khớp với các thư mục:
for d in */ ; do
echo "$d"
done
[[ -L $d ]]
xem $ d có phải là một liên kết tượng trưng hay không.
set -P
chỉ ảnh hưởng đến các lệnh thay đổi thư mục. spunge.us/TNac
[[ -L "$f" ]]
sẽ không loại trừ các liên kết tượng trưng trong trường hợp này */
, bạn phải loại bỏ dấu gạch chéo với [[ -L "${f%/}" ]]
(xem Kiểm tra liên kết với dấu gạch chéo )
Bạn có thể kiểm tra với -d
:
for f in *; do
if [ -d "$f" ]; then
# $f is a directory
fi
done
Đây là một trong những toán tử kiểm tra tập tin .
if [[ -d "$f" && ! -L "$f" ]]
sẽ loại trừ các liên kết tượng trưng
if [[ "$f" = "*" ]]; then continue; fi
Coi chừng giải pháp của choroba, mặc dù thanh lịch, có thể gợi ra hành vi bất ngờ nếu không có thư mục nào có sẵn trong thư mục hiện tại. Ở trạng thái này, thay vì bỏ qua for
vòng lặp, bash sẽ chạy vòng lặp chính xác một lần khi d
bằng */
:
#!/usr/bin/env bash
for d in */; do
# Will print */ if no directories are available
echo $d
done
Tôi khuyên bạn nên sử dụng những điều sau đây để bảo vệ chống lại trường hợp này:
#!/usr/bin/env bash
for f in *; do
if [ -d ${f} ]; then
# Will not run if no directories are available
echo $f
fi
done
Mã này sẽ lặp qua tất cả các tệp trong thư mục hiện tại, kiểm tra xem có phải f
là thư mục không, sau đó lặp lại f
nếu điều kiện trả về đúng. Nếu f
bằng */
, echo $f
sẽ không thực thi.
shopt -s nullglob
.
Nếu bạn cần chọn nhiều tệp cụ thể hơn chỉ thư mục sử dụng find
và chuyển nó tới while read
:
shopt -s dotglob
find * -prune -type d | while IFS= read -r d; do
echo "$d"
done
Sử dụng shopt -u dotglob
để loại trừ các thư mục ẩn (hoặc setopt dotglob
/ unsetopt dotglob
trong zsh).
IFS=
để tránh chia tách tên tệp có chứa một trong số $IFS
, ví dụ:'a b'
xem câu trả lời của AsymLabs dưới đây để có thêm find
lựa chọn
chỉnh sửa:
Trong trường hợp bạn cần tạo một giá trị thoát từ trong vòng lặp while, bạn có thể phá vỡ lớp con phụ bằng thủ thuật này:
while IFS= read -r d; do
if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -prune -type d)
Bạn có thể sử dụng bash thuần cho điều đó, nhưng tốt hơn là sử dụng find:
find . -maxdepth 1 -type d -exec echo {} \;
(tìm thêm sẽ bao gồm các thư mục ẩn)
shopt -s dotglob
cho bash
đến bao gồm các thư mục ẩn. Bạn cũng sẽ bao gồm .
. Cũng lưu ý rằng đó -maxdepth
không phải là một tùy chọn tiêu chuẩn ( -prune
là).
dotglob
tùy chọn là thú vị nhưng dotglob
chỉ áp dụng cho việc sử dụng *
. find .
sẽ luôn bao gồm các thư mục ẩn (và cả thư mục hiện tại)
Điều này được thực hiện để tìm cả thư mục hiển thị và ẩn trong thư mục làm việc hiện tại, ngoại trừ thư mục gốc:
để chỉ lặp qua các thư mục:
find -path './*' -prune -type d
để bao gồm các liên kết tượng trưng trong kết quả:
find -L -path './*' -prune -type d
để làm một cái gì đó cho mỗi thư mục (không bao gồm symlink):
find -path './*' -prune -type d -print0 | xargs -0 <cmds>
để loại trừ các thư mục ẩn:
find -path './[^.]*' -prune -type d
để thực thi nhiều lệnh trên các giá trị được trả về (một ví dụ rất dễ hiểu):
find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c \
"printf 'first: %-40s' '{}'; printf 'second: %s\n' '{}'"
thay vì 'sh -c' cũng có thể sử dụng 'bash -c', v.v.
... -print0 | xargs -0 ...
nếu bạn không biết tên chính xác là gì.
find * | while read file; do ...
Bạn có thể lặp qua tất cả các thư mục bao gồm các thư mục ẩn (bắt đầu bằng dấu chấm) trong một dòng và nhiều lệnh với:
for file in */ .*/ ; do echo "$file is a directory"; done
Nếu bạn muốn loại trừ các liên kết tượng trưng:
for file in *; do
if [[ -d "$file" && ! -L "$file" ]]; then
echo "$file is a directory";
fi;
done
lưu ý: sử dụng danh sách */ .*/
hoạt động trong bash, nhưng cũng hiển thị các thư mục .
và ..
trong khi ở zsh, nó sẽ không hiển thị những lỗi này nhưng sẽ xuất hiện lỗi nếu không có tệp ẩn trong thư mục
Một phiên bản sạch hơn sẽ bao gồm các thư mục ẩn và loại trừ ../ sẽ có tùy chọn dotglob:
shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done
(hoặc setopt dotglob
trong zsh)
bạn có thể hủy đặt dotglob với
shopt -u dotglob
Điều này sẽ bao gồm đường dẫn đầy đủ trong mỗi thư mục trong danh sách:
for i in $(find $PWD -maxdepth 1 -type d); do echo $i; done
Sử dụng find
với -exec
để lặp qua các thư mục và gọi một hàm trong tùy chọn exec:
dosomething () {
echo "doing something with $1"
}
export -f dosomething
find -path './*' -prune -type d -exec bash -c 'dosomething "$0"' {} \;
Sử dụng shopt -s dotglob
hoặc shopt -u dotglob
để bao gồm / loại trừ các thư mục ẩn
ls -l | grep ^d
hoặc là:
ll | grep ^d
Bạn có thể đặt nó làm bí danh
ls
câu trả lời dựa trên câu hỏi này, trong đó liệt kê các thư mục .
ls
: mywiki.wooledge.org/ParsingLs