Cách liệt kê các tệp không có thư mục và lọc theo tên (tùy chọn ls)


42

Tôi có một thư mục được gọi uploads. Nó chứa một loạt các tệp, cộng với một vài thư mục con mà lần lượt chứa các tệp.

Có cách nào tôi có thể (trong một bước) làm như sau:

  1. Liệt kê CHỈ các tệp trong thư mục tải lên gốc - Tôi không muốn thấy tên thư mục con hoặc nội dung của chúng;

  2. KHÔNG liệt kê bất kỳ tập tin nào bắt đầu bằng t_

Tôi biết về -dcờ, nhưng nó không giúp tôi đạt được điều mình muốn.

Câu trả lời:


53

Điều này nghe có vẻ như một công việc cho find.

  • Sử dụng -maxdepthđể chỉ trả về thư mục hiện tại, không tìm kiếm đệ quy bên trong các thư mục con
  • Sử dụng -type fđể chỉ trả lại các tập tin và không phải các thư mục hoặc nút thiết bị hoặc bất cứ điều gì khác
  • Sử dụng kết hợp nếu -not-nameđể tránh các tệp có tên bạn không muốn

Nó có thể đi cùng nhau như thế này:

find /path/to/uploads -maxdepth 1 -type f -not -name 't_*'

Cảm ơn! Tôi khá mới với CLI và chưa bao giờ sử dụng find. Tôi chắc chắn sẽ nhìn xa hơn vào nó.
EmmyS

2
@EmmyS: Bạn có thể tìm thấy thêm một mẹo nhỏ hữu ích ở đây. @Gilles đã đề cập bằng cách sử dụng -exec ls -lG -- {} +trong câu trả lời của mình để có được đầu ra bằng cách sử dụng các tùy chọn bổ sung cho ls. Bạn cũng có thể thêm chỉ một -lsphát hiện này để có được xấp xỉ nhanh chóng và bẩn về chế độ xem chi tiết của ls.
Caleb

18

GNU ls (tức là lệnh ls trên các hệ thống Linux không nhúng và Cygwin, cũng có sẵn trên một số thông báo khác) có một tùy chọn để ẩn một số tệp, dựa trên tên của chúng. Không có cách nào để bỏ qua các thư mục mặc dù.

ls --hide='t_*' uploads

Một cách tiếp cận khác là làm cho vỏ của bạn làm khớp. Bash, ksh và zsh có mẫu phủ định !(t_*)để khớp với tất cả các tệp ngoại trừ các tệp khớp t*; trong bash, tính năng này cần được bật shopt -s extglobvà trong zsh, nó cần được bật setopt ksh_glob. Zsh cũng có cú pháp tương đương ^t_*cần được bật setopt extended_glob. Điều này vẫn không bỏ qua các thư mục. Zsh có một tính năng bổ sung cho phép khớp các tệp không chỉ theo tên mà còn theo siêu dữ liệu và hơn thế nữa: vòng loại toàn cầu . Thêm (.)vào cuối của một trận đấu để hạn chế các tập tin thông thường. Việc phủ định ^là một phần của cú pháp khớp tên, do đó, ^t_*(.)có nghĩa là tất cả các tệp thông thường không khớp với t_*và không phải tất cả các tệp không khớp với các tệp thông thường t_*.

setopt extended_glob  # put this in your ~/.zshrc
ls uploads/^t_*(.)

Nếu bạn thấy mình không có các công cụ nâng cao, bạn có thể thực hiện việc này trên bất kỳ unix nào với find. Đây không phải là thứ bạn thường gõ trên dòng lệnh, nhưng nó mạnh mẽ và chính xác. Caleb đã chỉ ra cách thực hiện điều này với GNU find . Các -maxdepthtùy chọn là không cầm tay; -prunethay vào đó, bạn có thể sử dụng để dừng findđệ quy.

find uploads/* -type d -prune -o \! -type f -name 't_*' -print

Thay thế -printbằng -exec ls -lG -- {} +để thực hiện lsvới các tùy chọn yêu thích của bạn trên các tập tin.

Tất cả các lệnh trên đều ẩn các tệp chấm (tức là các tệp có tên bắt đầu bằng a .). Nếu bạn muốn hiển thị chúng, chuyển -Ađến lshoặc thêm Dvòng loại toàn cầu trong zsh ( ls uploads/^t_*(.D)). Với find, bạn có thể sử dụng một cách tiếp cận khác để làm cho nó chỉ lặp lại một cấp độ ( findkhông xử lý các tệp chấm đặc biệt). Điều này chỉ hoạt động đầy đủ nếu bạn chạy findtrong thư mục hiện tại.

cd uploads && find . -name . -o -type d -prune -o \! -type f -name 't_*' -print

3
Bạn có một dayjob? ;-) Tôi liên tục ngạc nhiên về độ dài và mức độ chi tiết của câu trả lời của bạn, ngay cả với những câu hỏi đơn giản nhất ở đây tại Unix SE! .. Dù sao thì hãy tiếp tục! :)
alex

Cảm ơn! Chi tiết rõ ràng. Tôi không biết mình có "công cụ nâng cao" hay không ngay bây giờ; Tôi đang sử dụng máy Mac tại nơi làm việc (mặc dù Linux ở nhà, vì vậy tôi chắc chắn rằng điều này sẽ có ích vào một lúc nào đó.)
EmmyS

@EmmyS: Đối với hộp linux của bạn, việc sử dụng của tôi -maxdepthnên hoạt động, nhưng vấn đề "tính di động" mà Gilles đề cập đến là BSD find(cũng được tìm thấy trên OSX tôi nghĩ) là một động vật hơi khác, vì vậy bạn cũng có thể cần câu trả lời của anh ấy. @Gilles: +1 cho thủ thuật zsh!
Caleb

1
@Gilles: Một số ý kiến ​​không hay về những điều này prunexuất hiện trong đầu tôi, nhưng tôi sẽ để nó đi bằng cách đơn giản nói rằng khi tôi tự mò mẫm trên hệ thống của mình, số lần suy nghĩ " lệnh này sẽ hoạt động nếu tôi tiếp tục AIX, Solaris hoặc MINIX3 "xấp xỉ ... ở chế độ chờ ... Tôi đang gặp khó khăn khi đọc đồng hồ ... màn hình bị đóng băng 0.00.
Caleb

2
Không có Gnu lscó một --use-telepathylựa chọn? Đó là cách nhanh nhất để chỉ hiển thị các tệp bạn muốn. Nó có thể không di động mặc dù.
dubiousjim

8
ls -l /folder | grep ^- | awk '{print $9}'

Có gì $9trong tuyên bố này?
EmmyS

3
@EmmyS Có nghĩa là trường / cột thứ 9 của đầu ra. Câu trả lời này đang cố gắng phân tích lsđầu ra .
jw013

print $ NF` sẽ tốt hơn, IMO. $ NF có nghĩa là số trường, sẽ là 9 và là cách sử dụng phổ biến trong AWK là cơ hội tốt để dạy cho những người khác về $ NF.
Elijah Lynn

1
ls -l | grep -v ^d | grep name$

Điều gì sẽ làm cho giải pháp này (đòi hỏi nhiều lệnh và đường ống) thích hợp hơn find?
HalosGhost

Nó ngắn gọn, dễ đọc và phù hợp với quy ước lệnh ls. Tôi thấy nó dễ nhớ hơn các đối số lệnh find. Để mỗi riêng của họ và danh tiếng cho các tùy chọn!
tkjef

0

Hãy để tôi cho nó một shot bằng cách sử dụng lsvà đường ống:

ls  -l --hide='t_*'  uploads/ | grep -v ^d | tr -s ' ' | cut -d ' ' -f 9

nói cột cuối cùng là cột thứ 9.


1
Nếu có tệp có khoảng trắng thì sao?
jordanm

0

Nếu vấn đề về tính di động -maxdepth của find là một mối quan tâm, bạn có thể sử dụng:

ls -l uploads/ | awk '/^-/ && $9 !~/^t_/ {print $9}'

Tôi không phải là một chuyên gia, nhưng tôi nghĩ rằng điều này sẽ làm việc. Tôi cho rằng nó trông hơi khó hiểu, nhưng nếu bạn nói awk, nó thực sự không. $ NF có thể được sử dụng thay vì $ 9. Bạn cũng có thể làm:

ls -l uploads/ | awk '/^-/' | awk '!/^t_/ {print $9}'

cái nào làm điều tương tự (nhưng có lẽ kém hiệu quả hơn cái trước ???).

Trên thực tế, sau khi suy nghĩ về các bài viết khác, có vẻ như

ls -l --hide=t_* uploads/ | awk '/^-/ {print $9}'

là một cách thậm chí ngắn hơn và rõ ràng hơn.

Ai đó làm ơn sửa tôi nếu tôi sai. :-)


Phân tích cú pháp lsnói chung không phải là một ý tưởng tốt . Thủ thuật awk của bạn sẽ thất bại với tên tệp có khoảng trắng trong đó.
Mat

@mat - Cảm ơn bạn đã sửa chữa. Sau khi đọc bài viết mà bạn (và jw013) đã chỉ ra, tôi thấy rằng ls không thể tin cậy để xuất tên tệp chính xác. Ngay cả khi tôi đã viết lại mã awk để in mọi thứ từ $ 9 đến cuối dòng (bao gồm cả khoảng trắng), đầu ra ls này vẫn có thể bị lỗi. Điều này thật đáng thất vọng và cần được sửa chữa IMO. Cảm ơn một lần nữa.
kkaszub

0

Tôi tìm thấy những cách ngắn này:

ls -p uploads | grep -Ev '/'

hoặc là

ls -pIt_* uploads | grep -v /

-1

Hãy thử bí danh này và sử dụng nó:

alias l='ls -hLlF'

ls -hLlFkhông hiển thị các thư mục con và nó hiển thị các tệp bắt đầu bằng t_. Vậy làm thế nào để trả lời câu hỏi này?
Raphael Ahren

Có lẽ tôi đã hiểu nhầm câu hỏi. ls -hLlF sẽ không hiển thị các thư mục đích của các thư mục được liên kết.
Dạng hạt

Có vẻ như vậy. Nhưng bạn đã không đọc các câu trả lời khác cho câu hỏi?
Raphael Ahren

-1

Dễ như ăn bánh:

ls -l --hide 't_*' <absolute path to desired directory> | grep -v ^d


(1) Câu trả lời này rất dễ, nó đã được đưa ra trước đây. (2) Tại sao bạn tin rằng bạn cần chỉ định đường dẫn đầy đủ đến thư mục?
Scott

@Scott - đây là một cách rất nhanh chóng và đơn giản để đi đến giải pháp. Đường dẫn đầy đủ được chỉ định để làm cho câu trả lời trở nên phổ biến ...
Digger
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.