我在多个目录中有一组文件。他们中的大多数都有一个相关的对,具有不同的扩展名和相同的基本名称。相关文件始终位于同一目录中。我需要在包含所有子目录的目录中仅列出没有对的文件(和路径)。我怎么能用bash做到这一点?
[ "foo", "foo\",bar", "bar" ]
非常感谢任何帮助!
答案 0 :(得分:2)
您可以使用find和pipe to perl对数据进行排序
find . -type f -print0 |\
perl -0 -l012 -ne 'if(/.*\/(.*)\./){$x{$1}++;$y{$1}=$_}
}{for(keys %x){print $y{$_} if $x{$_}==1}'
这为每个匹配的哈希和增量添加了没有后缀的名称,同时将整行添加到具有相同键的另一个哈希。
最后,它只检查哪一个匹配并打印。
由于文件名以空分隔,因此它应该适用于所有文件名。
答案 1 :(得分:1)
您可以列出目录下的所有文件,然后计算在相同路径名称(不包括扩展名)的同一树目录中可以找到的全名匹配项数。
如果您的文件与较少或一个名称匹配,则表示它没有“随播”文件:
for f in $(find -type f); do
c=$(find -wholename "$(echo $f | rev | cut --complement -d . -f 1 | rev).*" | wc -l);
if [ "$c" -le "1" ]; then echo $f; fi;
done
修改强>
如果模式组合在不同的行中执行,则可能更具可读性:
for f in $(find -type f); do
compPattern="$(echo $f | rev | cut --complement -d . -f 1 | rev).*"
c=$(find -wholename "$compPattern" | wc -l);
if [ "$c" -le "1" ]; then echo $f; fi;
done
修改(2)
为避免解析find
的输出,您可以使用read:
find -type f | while read f; do
if [ $(find -wholename "$(echo $f | rev | cut --complement -d . -f 1 | rev).*" | wc -l) -le "1" ]; then echo $f; fi;
done
修改(3)强>
要处理特殊字符,空格等,您可以使用以下内容。
while IFS= read -r -d '' f ; do
c=$(find -wholename "$(echo $f | rev | cut --complement -d . -f 1 | rev).*" | wc -l);
if [ "$c" -le "1" ]; then echo $f; fi;
done < <(find -type f -print0)