Bash循环目录包括隐藏文件

时间:2014-10-15 11:47:23

标签: linux bash

我正在寻找一种方法,在bash中对我的目录所包含的内容进行简单的循环,即文件,目录和链接,包括隐藏的内容。

我更愿意,如果它可以专门用于bash,但它必须是最一般的。当然,文件名(和目录名)可以有空格,断行,符号。除了“/”和ASCII NULL(0×0)之外的所有内容,即使在第一个字符处也是如此。此外,结果应排除'。'和'..'目录。

这是循环必须处理的文件生成器:

#!/bin/bash
mkdir -p test
cd test
touch A 1 ! "hello world" \$\"sym.dat .hidden " start with space" $'\n start with a newline' 
mkdir -p ". hidden with space" $'My Personal\nDirectory'

所以我的循环看起来应该是(但必须处理上面棘手的事情):

for i in * ;
  echo ">$i<"
done

我最接近的尝试是ls和bash数组的使用,但它无法使用,是:

IFS=$(echo -en "\n\b")
l=( $(ls -A .) )
for i in ${l[@]} ; do
echo ">$i<"
done
unset IFS

或者使用bash数组,但不排除“..”目录:

IFS=$(echo -en "\n\b")
l=( [[:print:]]* .[[:print:]]* )
for i in ${l[@]} ; do
echo ">$i<"
done
unset IFS

4 个答案:

答案 0 :(得分:12)

*.开头的文件不匹配,因此您只需要明确:

for i in * .[^.]*; do
    echo ">$i<"
done

.[^.]*将匹配以.开头的所有文件和目录,后跟非.字符,后跟零个或多个字符。换句话说,它就像更简单的.*,但不包括...。如果您需要匹配..foo之类的内容,则可以将..?*添加到模式列表中。

答案 1 :(得分:1)

正如chepner在下面的评论中指出的那样,此解决方案假设您正在运行GNU bash以及GNU find GNU sort ......

可以阻止GNU find使用-maxdepth选项递归到子目录中。然后使用-print00x00字节结束每个文件名,而不是通常从-print获取的换行符。

sort -z0x00字节之间的文件名进行排序。

然后,您可以使用sed删除点和点点目录条目(尽管GNU find似乎已经排除了..

我还使用sed来读取每个文件名前面的./basename也可以这样做,但旧版系统没有basename,您可能不相信它可以正确处理时髦角色。

(这些sed命令每个都需要两种情况:一种用于字符串开头的模式,另一种用于0x00字节之间的模式。这些是如此难看我将它们拆分成单独的功能。)

read命令没有-z-0选项,就像某些命令一样,但您可以使用-d ""伪造它并清空IFS环境变量。

附加-r选项可防止反斜杠换行组合被解释为行继续。 (另一个名为backslash\\nnewline的文件会被修改为backslashnewline。)如果其他反斜杠组合被解释为转义序列,则可能值得一看。

remove_dot_and_dotdot_dirs()
{
    sed \
      -e 's/^[.]\{1,2\}\x00//' \
      -e 's/\x00[.]\{1,2\}\x00/\x00/g'
}

remove_leading_dotslash()
{
    sed \
      -e 's/^[.]\///' \
      -e 's/\x00[.]\//\x00/g'
}

IFS=""
find . -maxdepth 1 -print0 |
  sort -z |
  remove_dot_and_dotdot_dirs |
  remove_leading_dotslash |
  while read -r -d "" filename
  do
      echo "Doing something with file '${filename}'..."
  done

答案 2 :(得分:0)

尝试使用find命令,例如:

find .

这将列出所有递归目录中的所有文件。

仅输出不包括前导的文件。或者..尝试:

find . -type f -printf %P\\n

答案 3 :(得分:0)

这可能不是最有利的方式,但我尝试了下面的事情

while read line ; do echo $line; done <<< $(ls -a | grep -v -w ".")

检查我做的下面的踪迹 Check the output