递归列出没有ls,find或extendedglob的隐藏文件



作为练习,我为自己设定了使用 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 - 这是故意的吗?

最新更新