作为练习,我为自己设定了使用 bash 内置递归列出文件的任务。我特别不想使用 ls 或 find,我宁愿不使用 setopt extendedglob。以下内容似乎有效,但我看不到如何使用/.* 扩展它以列出隐藏文件。有没有简单的解决方法?
g() { for k in "$1"/*; do # loop through directory
[[ -f "$k" ]] && { echo "$k"; continue; }; # echo file path
[[ -d "$k" ]] && { [[ -L "$k" ]] && { echo "$k"; continue; }; # echo symlinks but don't follow
g "$k"; }; # start over with new directory
done; }; g "/Users/neville/Desktop" # original directory
后来添加:对不起 - 我应该说:"OS X 上的 bash-3.2"
更改
for k in "$1"/*; do
自
for k in "$1"/* "$1"/.[^.]* "$1"/..?*; do
第二个 glob 匹配名称以点开头后跟点以外的任何内容的所有文件,而第三个 glob 匹配名称以两个点开头后跟某些内容的所有文件。在它们两者之间,它们将匹配除条目之外的所有隐藏文件 .
和 ..
.
不幸的是,除非设置了 shell 选项nullglob
,否则如果没有名称匹配的文件(在第三个文件中极有可能),这些(如第一个 glob)可能会保持原样,因此有必要验证名称是否确实是一个文件。
另一种方法是使用更简单的 glob "$1"/.*
,它将始终匹配.
和..
目录条目,因此将始终被替换。在这种情况下,有必要从列表中删除这两个条目:
for k in "$1"/* "$1"/.*; do
if ! [[ $k =~ /..?$ ]]; then
# ...
fi
done
(不过,"$1"/*
仍然可以保留在列表中。所以这并没有多大帮助。
将 GLOBIGNORE 文件设置为排除 .
和 ..
,这会隐式打开 "shopt -u dotglob"。 然后,您的原始代码无需其他更改即可工作。
user@host [/home/user/dir]
$ touch file
user@host [/home/user/dir]
$ touch .dotfile
user@host [/home/user/dir]
$ echo *
file
user@host [/home/user/dir]
$ GLOBIGNORE=".:.."
user@host [/home/user/dir]
$ echo *
.dotfile file
请注意,这是特定于 bash 的。 特别是,它在 ksh 中不起作用。
您可以指定多个参数来for
:
for k in "$1"/* "$1"/.*; do
但是,如果您确实在 目录中搜索.*
,您应该知道它还为您提供了.
和..
文件。如果 glob "$1"/*
匹配,您也可能得到一个不存在的文件,所以我也会检查一下。
考虑到这一点,这就是我纠正循环的方式:
g() {
local k subdir
for k in "$1"/* "$1"/.*; do # loop through directory
[[ -e "$k" ]] || continue # Skip missing files (unmatched globs)
subdir=${k##*/}
[[ "$subdir" = . ]] || [[ "$subdir" = .. ]] && continue # Skip the pseudo-directories "." and ".."
if [[ -f "$k" ]] || [[ -L "$k" ]]; then
printf %s\n "$k" # Echo the paths of files and symlinks
elif [[ -d "$k" ]]; then
g "$k" # start over with new directory
fi
done
}
g ~neville/Desktop
在这里,时髦的${k##*/}
只是获取文件基本名称的一种快速方法,而local
则被放入,以便变量不会修改 shell 中的任何现有变量。
我更改的另一件事是echo "$k"
printf %s\n "$k"
,因为echo
在参数处理方面存在不可救药的缺陷,应该避免以回显未知变量。(参见 Rich 的 sh 技巧来解释如何;它归结为 -n 和 -e 在作品中扔了一个扳手。
顺便说一句,这不会打印套接字或 fifo - 这是故意的吗?