Gunakan nama file untuk mem-parsing daftar jalur yang disimpan dalam file

9

Saya menjalankan Mac OSX dan mencoba menggunakan baris perintah untuk menemukan jumlah file yang saya miliki dengan nama yang sama.

Saya mencoba menggunakan perintah berikut:

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

Itu tidak bekerja! Ketika saya melakukan hal berikut:

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

Kemudian, duplikat_files berisi jalur semua file saya. Jadi saya pikir masalahnya adalah basename- tidak menerima input standar. Saya kemudian mencoba yang berikut:

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

tapi sekali lagi itu sepertinya tidak berhasil. Pencarian di internet sepertinya tidak menghasilkan banyak kegembiraan. Pikiran yang paling disambut.

JohnB
sumber

Jawaban:

16

basename beroperasi pada argumen baris perintahnya, tidak membaca dari input standar.

Anda tidak perlu memanggil basenameutilitas, dan Anda sebaiknya tidak: semua itu akan menghapus bagian sebelum yang terakhir /, dan itu akan lambat untuk memanggil perintah eksternal untuk setiap entri, Anda dapat menggunakan pemrosesan teks utilitas sebagai gantinya.

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

Mungkin lebih bermanfaat untuk melacak lokasi file. Menyortir berdasarkan nama memudahkan menemukan duplikat, tetapi sorttidak memiliki opsi untuk menggunakan bidang terakhir. Yang bisa Anda lakukan adalah menyalin bidang yang terakhir /dipisahkan ke awal, lalu mengurutkan, dan kemudian menggunakan sedikit pemrosesan ad hoc awk untuk mengekstrak dan menyajikan duplikat.

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

(Perhatikan bahwa saya berasumsi bahwa tidak ada nama file Anda yang mengandung karakter baris baru.)

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Super terima kasih. Inilah yang saya coba lakukan ... sangat berguna
JohnB
7

Mengapa tidak menggunakan findfitur builtin untuk menampilkan hanya nama file:

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

(mengasumsikan GNU find) atau setidaknya sesuatu seperti ini:

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

basename tidak dapat membaca melalui pipa atau memproses beberapa file sekaligus.

ps. Tidak perlu menentukan -name '*'apakah Anda ingin membuat daftar semua file. Ini adalah opsi default.

buru-buru
sumber
Terima kasih - '-printf' tidak berfungsi untuk OS X UNIX
JohnB
Dan ketika saya mencoba versi kedua saya dapatkan basename: unknown primary or operator. Terima kasih atas tipnya-name "*"
JohnB
Itu aneh. Saya dapat melihat -printfbahkan di halaman manual posix. Tentang kesalahan dengan cara kedua, itu karena kesalahan ketik dalam jawaban saya. Tetap. Bisakah Anda mencobanya sekali lagi?
buru
Juga dengan -printfsaya mendapatkan -printf: unknown primary or operator. Juga ketika saya memeriksa Unix dalam buku referensi Nutshell yang terdaftar sebagai opsi GNU / Linux - tidak mengatakan apa-apa tentang OSX
JohnB
1
Sebenarnya sumber terbaik ada man finddi konsol Anda :)
buru
4

Ini sepertinya bekerja untuk saya di OSX:

find ~ -type f -exec basename -a {} + | sort | uniq -d
rahmu
sumber
Ya - ini bagus, terima kasih - karena minat, apa arti +dari perintah itu?
JohnB
2
Apakah ini berguna tolong pertimbangkan untuk memilihnya.
tersangka
Itu - saya tidak bisa memilih beacuase saya butuh 15 reputasi :-(
JohnB
@StephaneChazelas: Menurut halaman manual untuk nama BSD , executable dapat mengambil banyak string sebagai argumen. Saya periksa dua kali pada OSX, itu berfungsi.
rahmu
1
Baiklah maaf, saya berdiri terkoreksi. Saya tidak mengetahui ekstensi BSD itu. Namun, itu masih gagal jika hanya ada dua file. Anda perlu menambahkan -aopsi untuk menutupi kasus itu juga.
Stéphane Chazelas
2

Alternatif (tidak mengasumsikan baris baru dalam nama file):

find ~ -type f | awk -F/ '{print $NF}' | sort | uniq -d
Stéphane Chazelas
sumber
2

Anda dapat menggunakan xargsdengan basenameuntuk mendapatkan output yang diinginkan, seperti ini:

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

Dengan versi terbaru bashyang menangani array asosiatif, berikut ini akan menangani nama path tambahan dengan baris baru yang disematkan:

#!/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

Ini tidak menggunakan utilitas eksternal.

Kusalananda
sumber