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


9

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

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

回答:


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

7

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

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

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

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

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

ps。-name '*'すべてのファイルをリストするかどうかを指定する必要はありません。これはデフォルトのオプションです。


ありがとう-'-printf'はOS X UNIXでは機能しません
JohnB

そして、私が2番目のバージョンを試すと、私は得basename: unknown primary or operatorます。ヒントをありがとう-name "*"
JohnB 2014年

それは奇妙だ。-printfposixのmanページでも見ることができます。二番目の方法でのエラーについて、それは私の答えのタイプミスの原因です。修繕。もう一度試していただけませんか。
ラッシュ

また、-printf私は-printf: unknown primary or operator。また、NutshellリファレンスブックでUnixをチェックしたところ、GNU / Linuxオプションとしてリストされていました
-OSX

1
実際、最良のソースはman findコンソールにあります:)
急い

4

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

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

はい-これは大きな感謝です-興味深いことに+、コマンドで何を意味しますか?
JohnB 2014年

2
これは便利ですか?投票することを検討してください。
容疑者2014年

それは-私は15の評判を必要とするため投票できません:-(
JohnB

@StephaneChazelas:BSD basenameのmanページによると、実行可能ファイルは複数の文字列を引数としてとることができます。私はOSXでダブルチェックしました、それは動作します。
rahmu 2014年

1
申し訳ありませんが、私は修正されたスタンドです。私はそのBSD拡張に気づいていませんでした。ただし、ファイルが2つしかない場合でも失敗します。その場合もカバーする-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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.