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

时间:2016-01-18 20:23:34

标签: bash recursion hidden-files built-in

作为一项练习,我为自己设置了使用bash builtins递归列出文件的任务。我特别不想使用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

稍后添加:抱歉 - 我应该说:' bash-3.2 on OS X'

3 个答案:

答案 0 :(得分:2)

更改

for k in "$1"/*; do

for k in "$1"/* "$1"/.[^.]* "$1"/..?*; do

第二个glob匹配所有名称以点开头,后跟除点之外的文件的文件,而第三个匹配所有名称以两个点后跟的东西的文件。在他们两个之间,他们将匹配条目...以外的所有隐藏文件。

不幸的是,除非设置了shell选项nullglob,否则那些(如第一个glob)可以保持原样,如果没有名称匹配的文件(非常可能是第三个),所以它有必要验证该名称实际上是一个文件。

另一种方法是使用更简单的glob "$1"/.*,它总是匹配...目录条目,因此总是被替换。在这种情况下,有必要从列表中删除两个条目:

for k in "$1"/* "$1"/.*; do
  if ! [[ $k =~ /\.\.?$ ]]; then
    # ...
  fi
done

"$1"/*仍然可以留在列表中。所以这并没有多大帮助。)

答案 1 :(得分: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中不起作用。

答案 2 :(得分:0)

您可以为ProgrammingError: SELECT DISTINCT ON expressions must match initial ORDER BY expressions指定多个参数:

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##*/}以便变量不会修改任何现有变量外壳

我改变的另一件事是localecho "$k",因为printf %s\\n "$k"在其参数处理中无可挽回地存在缺陷,应该避免为了回显未知变量。 (有关如何解释,请参阅Rich's sh tricks;它归结为-n和-e在工作中抛出扳手。)

顺便说一句,这不会打印套接字或fifos - 这是故意的吗?