Sử dụng tên cơ sở để phân tích danh sách các đường dẫn được giữ trong một tệp


9

Tôi đang chạy Mac OSX và cố gắng sử dụng dòng lệnh để tìm số lượng tệp tôi có cùng tên.

Tôi đã thử sử dụng lệnh sau:

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

Nó không hoạt động! Khi tôi làm như sau:

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

Sau đó, repeat_files không chứa đường dẫn của tất cả các tệp của tôi. Vì vậy, tôi nghĩ rằng vấn đề là với basename- nó không chấp nhận đầu vào tiêu chuẩn. Sau đó tôi đã thử như sau:

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

nhưng một lần nữa điều đó dường như không hoạt động. Tìm kiếm trên internet dường như không mang lại nhiều niềm vui. Mọi suy nghĩ đều được chào đón.

Câu trả lời:


16

basename hoạt động trên đối số dòng lệnh của nó, nó không đọc từ đầu vào tiêu chuẩn.

Bạn không cần phải gọi basenametiện ích, và tốt hơn hết là không nên: tất cả những gì sẽ làm là loại bỏ phần trước phần cuối /và sẽ rất chậm khi gọi lệnh bên ngoài cho mỗi mục, bạn có thể sử dụng xử lý văn bản tiện ích thay thế.

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

Nó có thể hữu ích hơn để theo dõi vị trí của các tập tin. Sắp xếp theo tên giúp dễ dàng xác định vị trí trùng lặp, nhưng sortkhông có tùy chọn để sử dụng trường cuối cùng. Những gì bạn có thể làm là sao chép /trường phân tách cuối cùng vào đầu, sau đó sắp xếp và sau đó sử dụng một chút xử lý ad hoc awk để trích xuất và trình bày các bản sao.

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

(Lưu ý rằng tôi cho rằng không có tên tệp nào của bạn chứa ký tự dòng mới.)


Siêu cảm ơn. Đây chính xác là những gì tôi đã cố gắng làm ... rất hữu ích
JohnB

7

Tại sao không sử dụng findcác tính năng dựng sẵn để xuất tên tệp:

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

(giả sử GNU find) hoặc ít nhất là một cái gì đó như thế này:

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

basename không thể đọc qua đường ống hoặc xử lý nhiều tệp cùng một lúc.

ps. Không cần chỉ định -name '*'nếu bạn muốn liệt kê tất cả các tệp. Đây là một tùy chọn mặc định.


Cảm ơn - '-printf' không hoạt động cho OS X UNIX
JohnB

Và khi tôi thử phiên bản thứ hai tôi nhận được basename: unknown primary or operator. Cảm ơn về mẹo trên-name "*"
JohnB

Điều đó thật lạ. Tôi có thể nhìn thấy -printfngay cả trong trang người đàn ông posix. Về lỗi với cách thứ hai, đó là nguyên nhân của lỗi đánh máy trong câu trả lời của tôi. Đã sửa. Bạn có thể vui lòng thử lại một lần nữa không?
vội vàng

Ngoài ra với -printftôi nhận được -printf: unknown primary or operator. Ngoài ra khi tôi kiểm tra Unix trong một cuốn sách tham khảo Nutshell, nó liệt kê dưới dạng tùy chọn GNU / Linux - không nói gì về OSX
JohnB

1
Trên thực tế, nguồn tốt nhất sẽ có man findtrong bảng điều khiển của bạn :)
vội vàng

4

Điều này dường như hoạt động với tôi trên OSX:

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

Vâng - đây là lời cảm ơn tuyệt vời - không quan tâm đến việc +biểu thị trong lệnh là gì?
JohnB

2
Đây có phải là hữu ích xin vui lòng xem xét bỏ phiếu lên.
suspectus

Đó là - Tôi không thể bỏ phiếu beacuase tôi cần 15 danh tiếng :-(
JohnB

@StephaneChazelas: Theo trang man cho tên cơ sở BSD , tệp thực thi có thể lấy nhiều chuỗi làm đối số. Tôi đã kiểm tra lại trên OSX, nó hoạt động.
rahmu

1
Được rồi xin lỗi, tôi đứng sửa. Tôi đã không biết về phần mở rộng BSD đó. Tuy nhiên, điều đó vẫn thất bại nếu có chính xác hai tệp. Bạn cũng cần thêm -atùy chọn để bao quát cho trường hợp đó.
Stéphane Chazelas

2

Các lựa chọn thay thế (giả sử không có dòng mới trong tên tệp):

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

2

Bạn có thể sử dụng xargsvới basenameđể có được đầu ra mong muốn, như thế này:

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

0

Với phiên bản gần đây bashxử lý các mảng kết hợp, sau đây sẽ xử lý thêm các tên đường dẫn với các dòng mới được nhúng:

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

Điều này sử dụng không có tiện ích bên ngoài.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.