使用basename解析文件中包含的路径列表


9

我正在运行Mac OSX,并尝试使用命令行查找具有相同名称的文件数。

我尝试使用以下命令:

find ~ -type f -name "*" -print | basename | sort | uniq -d > duplicate_files

它不起作用!当我执行以下操作时:

find ~ -type f -name "*" -print > duplicate_files

然后plicate_files确实包含了我所有文件的路径。因此,我认为问题出在basename-它不接受标准输入。然后,我尝试了以下操作:

basename $(find ~ -type f -name "*" -print) > duplicate_files

但这又似乎不起作用。在互联网上搜索似乎并没有带来太多乐趣。任何想法最欢迎。

Answers:


16

basename 在其命令行参数上操作,它不会从标准输入中读取。

您不需要调用该basename实用程序,最好不要:只做最后一个部分就将其剥离/,并且为每个条目调用外部命令会很慢,您可以使用文本处理实用程序代替。

find ~ -type f | sed 's!.*/!!' | sort | uniq -d

跟踪文件的位置可能更有用。按名称排序使查找重复项更容易,但sort没有使用最后一个字段的选项。您可以做的是将最后一个/分隔的字段复制到开头,然后进行排序,然后使用一些临时的awk处理来提取并显示重复项。

find ~ -type f |
sed 's!.*/\(.*\)!\1/&!' |   # copy the last field to the beginning
sort -t/ -k1,1 |
cut -d/ -f2- |   # remove the extra first field (could be combined with awk below)
awk -F / '{
    if ($NF == name) {
        if (previous != "") {print previous; previous = ""}
        print
    } else {
        previous = $0
        name = $NF
    }
'

(请注意,我假设您的文件名都不包含换行符。)


超级谢谢。这正是我正在尝试做的...非常有用
JohnB 2014年

7

为什么不使用内置find功能仅输出文件名:

find ~ -type f -printf '%f\n' | sort | uniq -c

(假设为GNU find)或至少类似以下内容:

find ~ -exec basename {} \; | sort | uniq -c

basename 无法通过管道读取或一次处理多个文件。

ps。无需指定-name '*'是否要列出所有文件。这是默认选项。


谢谢
-'-printf

当我尝试第二个版本时,我得到了basename: unknown primary or operator。感谢您给我的提示-name "*"
JohnB 2014年

那很奇怪。我-printf什至可以在posix手册页中看到。关于第二种方式的错误,这是我回答中输入错误的原因。固定。您能再试一次吗?

另外随着-printf我得到的-printf: unknown primary or operator。另外,当我在Nutshell参考书中检查Unix时,它被列为GNU / Linux选项-没有说关于OSX的内容
JohnB 2014年

1
实际上,最好的来源是man find在您的控制台中:)
匆匆忙忙

4

这似乎在OSX上对我有用:

find ~ -type f -exec basename -a {} + | sort | uniq -d

是的-非常感谢-出于兴趣+,命令中的含义是什么?
JohnB 2014年

2
这是否有用,请考虑对其进行投票。
嫌疑犯

是-我不能投票,因为我需要15个声誉:-(
JohnB 2014年

@StephaneChazelas:根据BSD basename手册页,可执行文件可以使用多个字符串作为参数。我在OSX上仔细检查过,它可以正常工作。
rahmu 2014年

1
好的,对不起,我已经纠正了。我不知道该BSD扩展。但是,如果恰好有两个文件,那仍然会失败。您还需要添加-a选项以涵盖该情况。
斯特凡Chazelas


2

您可以使用xargswith basename获得所需的输出,如下所示:

find ~ -type f -name "*" -print | xargs -l basename | sort | uniq -d > duplicate_files

0

对于bash处理关联数组的最新版本,以下代码将另外处理带有嵌入式换行符的路径名:

#!/bin/bash

topdir=$HOME

shopt -s globstar  # enable the ** glob

declare -A count

# count the number of times each filename (base name) occurs
for pathname in "$topdir"/**; do
    # skip names that are not regular files (or not symbolic links to such files)
    [ ! -f "$pathname" ] && continue

    # get the base name
    filename=${pathname##*/}

    # add one to this base name's count
    count[$filename]=$(( ${count[$filename]} + 1 ))
done

# go through the collected names and print any name that
# has a count greater than one
for filename in "${!count[@]}"; do
    if [ "${count[$filename]}" -gt 1 ]; then
        printf 'Duplicate filename: %s\n' "$filename"
    fi
done

这不使用外部实用程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.