我有一个目录,其中有多个子目录。我正在一一循环子目录。然后我使用 cd 更改目录。如果在该子目录中,我有一个扩展名为 .partial 的文件,请保存文件名。然后我需要打印子目录名称和部分文件名。我写过这样的东西
for f in *
do
if [ -d "$f" ]; then
cd "$f"
a=$(find ./ -name "*.partial")
if [ -e "$a" ];then
echo -e "$f" "\t" "$a"
fi
cd ..
fi
done
问题是它会在进一步的子目录中find
递归地查找文件扩展名,这是我不想要的。.partial
如何将其限制为仅当前目录?
答案1
仅输出.partial
相对于当前目录的每个文件的完整路径名:
printf '%s\n' ./*/*.partial
如果没有匹配,设置nullglob
shell 选项将使其不输出模式本身(仍然会输出空行),并且设置还会匹配隐藏名称。bash
dotglob
以下将这些路径名拆分为目录路径和文件名部分:
for name in ./*/*.partial; do
[ -f "$name" ] && printf '%s\t%s\n' "${name%/*}" "${name##*/}"
done
这将打印在当前目录的任何子目录中找到的.partial
每个名称的子目录名称和文件名。.partial
在 中,如果您还需要能够匹配隐藏名称,bash
您可能还需要设置 shell 选项。dotglob
dirname
这两个参数替换可以通过调用和来替换basename
:
for name in ./*/*.partial; do
[ -f "$name" ] && printf '%s\t%s\n' "$(dirname "$name")" "$(basename "$name")"
done
上述内容的变体,仅打印一次子目录名称(这需要一个bash
类似 shell 的${*%%*/}
参数扩展,它为每个位置参数删除目录路径并保留文件名):
IFS=$'\t'
for dirname in ./*/; do
set -- "$dirname"/*.partial;
[ -f "$1" ] && printf '%s\t%s\n' "$dirname" "${*##*/}"
done
这会循环遍历每个子目录并扩展*.partial
每个子目录中的通配模式。如果第一个匹配是常规文件(或某个文件的链接),则打印子目录名称,后跟与模式匹配的名称,并删除目录路径。
答案2
该find
实用程序支持该选项-maxdepth
-max深度级别
下降到起始点以下目录的最多级别(非负整数)级别。 -maxdepth 0 表示仅将测试和操作应用于起点本身。
要限制find
到指定目录,可以添加选项-maxdepth 1
。
如果您尝试列出*.partial
深度为 2 的所有常规文件,其输出与您的问题中的输出类似,您可以尝试以下命令
find . -mindepth 2 -maxdepth 2 -type f -name '*.partial' -printf '%h\t./%f\n'
这可能会给出类似的输出
./b ./file2.partial
./b ./file3.partial
./a ./file1.partial
答案3
如果你有 GNUfind
你可以做这样的事情
for dir in *
do
files=$(find "$dir" -maxdepth 1 -type f -name '*.partial' -printf "%f\n" | xargs)
[[ -n "$files" ]] && printf "%s\t%s\n" "$dir" "$files"
done
如果你没有 GNU,你可以以牺牲一些效率为代价来find
模拟,就像这样-printf '%f\n'
for dir in *
do
files=$(cd "$dir" && find . -maxdepth 1 -type f -name '*.partial' -print | sed 's!^./!!' | xargs)
[[ -n "$files" ]] && printf "%s\t%s\n" "$dir" "$files"
done
这两种解决方案都不能处理带有换行符或奇怪打印字符的文件,但如果您在单行上列出目录中的文件,我希望您不会有奇怪的文件名。如果您的 shell 无法理解,[[ ... ]]
只需将双括号替换为单括号即可[ ... ]
。