我正在寻找一种方法来对目录中包含的所有内容(包括文件,目录和链接,包括隐藏目录)进行简单的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
and 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
正如chepner在下面的评论中指出的那样,该解决方案假定您正在将GNU bash
和GNU find
GNU 一起运行sort
。
find
使用该-maxdepth
选项可以防止GNU 递归到子目录中。然后使用-print0
每个文件名以一个0x00
字节结尾,而不是通常从中得到的换行符-print
。
该sort -z
排序的文件名0x00
字节。
然后,您可以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
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句