web-dev-qa-db-ja.com

basenameを使用して、ファイルに保持されているパスのリストを解析します

Mac OSXを実行していて、コマンドラインを使用して、同じ名前のファイルの数を見つけようとしています。

次のコマンドを使用しようとしました。

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

動かない!私が次のことをすると:

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

次に、duplicate_filesにはすべてのファイルのパスが含まれています。だから私は問題がbasenameにあると思います-標準入力を受け付けません。それから私は以下を試しました:

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

しかし、それでもうまくいかないようです。インターネットでの検索はあまり喜びをもたらしていないようです。どんな考えでも大歓迎です。

9
JohnB

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
    }
'

(私はあなたのファイル名のどれも改行文字を含まないと仮定していることに注意してください。)

組み込みのfind機能を使用してファイル名だけを出力しないのはなぜですか。

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

(GNU find)または少なくとも次のようなものを想定:

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

basenameは、パイプ経由で読み取ることも、複数のファイルを一度に処理することもできません。

ps。すべてのファイルを一覧表示する場合は、-name '*'を指定する必要はありません。これはデフォルトのオプションです。

7
rush

これは私にとってOSXではうまくいくようです:

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

代替案(ファイル名に改行がないと想定):

find ~ -type f | awk -F/ '{print $NF}' | sort | uniq -d
2

次のように、xargsbasenameとともに使用して、目的の出力を取得できます。

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

連想配列を処理する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

これは外部ユーティリティを使用しません。

0
Kusalananda