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.

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.)


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.


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

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

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

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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.