我正在寻找一种方法来在我的目录包含的所有内容上进行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'
Run Code Online (Sandbox Code Playgroud)
所以我的循环应该看起来像(但必须处理上面棘手的东西):
for i in * ;
echo ">$i<"
done
Run Code Online (Sandbox Code Playgroud)
我最接近的尝试是使用ls
和bash数组,但它无法使用,是:
IFS=$(echo -en "\n\b")
l=( $(ls -A .) )
for i in ${l[@]} ; do
echo ">$i<"
done
unset IFS
Run Code Online (Sandbox Code Playgroud)
或者使用bash数组,但不排除".."目录:
IFS=$(echo -en "\n\b")
l=( [[:print:]]* .[[:print:]]* )
for i in ${l[@]} ; do
echo ">$i<"
done
unset IFS
Run Code Online (Sandbox Code Playgroud)
che*_*ner 12
*
与开头的文件不匹配.
,因此您只需要明确:
for i in * .[^.]*; do
echo ">$i<"
done
Run Code Online (Sandbox Code Playgroud)
.[^.]*
将匹配所有以.
.开头的文件和目录,后跟非.
字符,后跟零个或多个字符.换句话说,它就像更简单.*
,但排除.
和..
.如果你需要匹配类似的东西..foo
,那么你可以添加..?*
到模式列表中.
正如切普纳在下面的评论中指出的那样,该解决方案假设您正在运行 GNUbash
以及 GNU find
GNU sort
...
find
使用该选项可以防止GNU递归到子目录中-maxdepth
。然后用-print0
一个字节来结束每个文件名,0x00
而不是通常从-print
.
sort -z
对字节之间的文件名进行排序0x00
。
然后,您可以使用sed
来删除点和点-点目录条目(尽管 GNUfind
似乎..
已经排除了)。
我还习惯于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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4416 次 |
最近记录: |