简体   繁体   English

Bash循环目录包括隐藏文件

[英]Bash loop through directory including hidden file

I am looking for a way to make a simple loop in bash over everything my directory contains, ie files, directories and links including hidden ones. 我正在寻找一种方法来在我的目录包含的所有内容上进行bash的简单循环,即文件,目录和包含隐藏的链接。

I will prefer if it could be specifically in bash but it has to be the most general. 我更愿意,如果它可以特别在bash中,但它必须是最一般的。 Of course, file names (and directory names) can have white space, break line, symbols. 当然,文件名(和目录名)可以有空格,断行,符号。 Everything but "/" and ASCII NULL (0×0), even at the first character. 除了“/”和ASCII NULL(0×0)之外的所有内容,即使在第一个字符处也是如此。 Also, the result should exclude the '.' 此外,结果应排除'。' and '..' directories. 和'..'目录。

Here is a generator of files on which the loop has to deal with : 这是循环必须处理的文件生成器:

#!/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'

So my loop should look like (but has to deal with the tricky stuff above): 所以我的循环应该看起来像(但必须处理上面的棘手的东西):

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

My closest try was the use of ls and bash array, but it is not working with, is: 我最接近的尝试是使用ls和bash数组,但它无法使用,是:

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

Or using bash arrays but the ".." directory is not exclude: 或者使用bash数组,但不排除“..”目录:

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

* doesn't match files beginning with . *与以...开头的文件不匹配. , so you just need to be explicit: ,所以你只需要明确:

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

.[^.]* will match all files and directories starting with . .[^.]*将匹配以.开头的所有文件和目录. , followed by a non- . ,其次是非. character, followed by zero or more characters. 字符,后跟零个或多个字符。 In other words, it's like the simpler .* , but excludes . 换句话说,它就像更简单.* ,但不包括在内. and .. . .. If you need to match something like ..foo , then you might add ..?* to the list of patterns. 如果你需要匹配像..foo这样的..foo ,那么你可以将..?*添加到模式列表中。

As chepner noted in the comments below, this solution assumes you're running GNU bash along with GNU find GNU sort ... 正如chepner在下面的评论中指出的,这个解决方案假设你运行GNU bash以及GNU find GNU sort ...

GNU find can be prevented from recursing into subdirectories with the -maxdepth option. 可以使用-maxdepth选项阻止GNU find重新进入子目录。 Then use -print0 to end every filename with a 0x00 byte instead of the newline you'd usually get from -print . 然后使用-print00x00字节结束每个文件名,而不是通常从-print获取的换行符。

The sort -z sorts the filenames between the 0x00 bytes. sort -z0x00字节之间的文件名进行sort -z

Then, you can use sed to get rid of the dot and dot-dot directory entries (although GNU find seems to exclude the .. already). 然后,你可以使用sed摆脱点和点点目录条目(尽管GNU find似乎已经排除了.. )。

I also used sed to get read of the ./ in front of every filename. 我还使用sed来读取每个文件名前面的./ basename could do that too, but older systems didn't have basename , and you might not trust it to handle the funky characters right. basename也可以这样做,但是旧系统没有basename ,你可能不相信它可以正确处理时髦的角色。

(These sed commands each required two cases: one for a pattern at the start of the string, and one for the pattern between 0x00 bytes. These were so ugly I split them out into separate functions.) (这些sed命令每个都需要两种情况:一种用于字符串开头的模式,另一种用于0x00字节之间的模式。这些很难看,我将它们拆分成单独的函数。)

The read command doesn't have a -z or -0 option like some commands, but you can fake it with -d "" and blanking the IFS environment variable. read命令没有像某些命令那样的-z-0选项,但您可以使用-d ""伪造它并消隐IFS环境变量。

The additional -r option prevents a backslash-newline combo from being interpreted as a line continuation. 附加-r选项可防止反斜杠换行组合被解释为行继续。 (A file called backslash\\\\nnewline would otherwise be mangled to backslashnewline .) It might be worth seeing if other backslash-combos get interpreted as escape sequences. (一个名为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

Try the find command, something like: 尝试使用find命令,例如:

find .

That will list all the files in all recursive directories. 这将列出所有递归目录中的所有文件。

To output only files excluding the leading . 仅输出不包括前导的文件。 or .. try: 或..尝试:

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

It may not be the most favorable way but I tried bellow thing 它可能不是最有利的方式,但我尝试了下面的事情

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

check the below trail which I did 检查我做的下面的踪迹 检查输出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM