Nội dung ls của một thư mục bỏ qua các liên kết tượng trưng


16

Tôi có một thư mục mà tôi muốn liệt kê tất cả các nội dung (tệp và thư mục con) mà không hiển thị các liên kết tượng trưng. Tôi đang sử dụng các tiện ích GNU trên Linux. Các lsphiên bản là 8.13.

Thí dụ:

Danh sách đầy đủ thư mục:

~/test$ ls -Gg
total 12
drwxrwxr-x 2 4096 Jul  9 10:29 dir1
drwxrwxr-x 2 4096 Jul  9 10:29 dir2
drwxrwxr-x 2 4096 Jul  9 10:29 dir3
-rw-rw-r-- 1    0 Jul  9 10:29 file1
-rw-rw-r-- 1    0 Jul  9 10:29 file2
lrwxrwxrwx 1    5 Jul  9 10:29 link1 -> link1
lrwxrwxrwx 1    5 Jul  9 10:30 link2 -> link2

Những gì tôi muốn nhận được

~/test$ ls -somthing (or bash hack)
total 12
dir1 dir2 dir3 file1 file2

LƯU Ý: Động lực chính của tôi là thực hiện một grep đệ quy (GNU grep 2.10) mà không theo các liên kết tượng trưng.

Câu trả lời:


28

Đối với câu hỏi đã nêu, bạn có thể sử dụng find:

find . -mindepth 1 ! -type l

sẽ liệt kê tất cả các tệp và thư mục trong thư mục hiện tại hoặc bất kỳ thư mục con nào không phải là liên kết tượng trưng.

mindepth 1chỉ là để bỏ qua .mục nhập thư mục hiện tại. Thịt của nó là sự kết hợp của -type l, có nghĩa là "là một liên kết tượng trưng", và !, có nghĩa là phủ nhận thử nghiệm sau đây. Kết hợp chúng phù hợp với mọi tệp không phải là một liên kết tượng trưng. Điều này liệt kê tất cả các tệp và thư mục đệ quy, nhưng không có liên kết tượng trưng.

Nếu bạn chỉ muốn các tệp thông thường (và không phải thư mục):

find . -type f

Chỉ bao gồm các phần tử con trực tiếp của thư mục này và không bao gồm tất cả các phần tử khác theo cách đệ quy:

find . -mindepth 1 -maxdepth 1

Bạn có thể kết hợp các thử nghiệm (và khác) với nhau để có được danh sách các tệp bạn muốn.

Để thực hiện một cụ thể greptrên mỗi tệp khớp với các bài kiểm tra bạn đang sử dụng, hãy sử dụng -exec:

find . -type f -exec grep -H 'some pattern' '{}' +

Các '{}'sẽ được thay thế bằng các tập tin. Điều +cần thiết là nói findlệnh của bạn được thực hiện. Tùy chọn -Hbuộc grep hiển thị tên tệp ngay cả khi nó chạy với một tệp khớp duy nhất.


Nó không hiển thị các tập tin trong phù thủy mẫu được tìm thấy.
TheMeaningfulEngineer

Đó là những gì bạn chạy grepcho (xem đoạn cuối).
Michael Homer

Tôi không làm việc cho tôi. Nó chỉ xuất ra các mẫu tìm thấy mà không có tên tệp nơi nó được tìm thấy.
TheMeaningfulEngineer

2
Sử dụng grep -H, nếu bạn có nó (xem man grep), hoặc nếu không grep 'pat' '{}' /dev/null ';'để lừa nó nghĩ rằng có nhiều tệp nếu bạn không.
Michael Homer

1
+không đáp ứng yêu cầu đó trong trường hợp suy biến khi chỉ còn một tệp hoặc một tệp còn lại.
Michael Homer

15

Hoặc, đơn giản hơn:

ls -l | grep -v ^l

Giải trình

ls -lcó nghĩa là liệt kê ở dạng dài . Khi bạn làm điều này, chuỗi ký tự đầu tiên cung cấp thông tin về mỗi tệp. Ký tự đầu tiên cho biết mỗi loại tệp là gì. Nếu đó là một liên kết tượng trưng, ​​thì an llà ký tự đầu tiên.

grep -v ^lcó nghĩa là lọc ra ( -v) các dòng bắt đầu bằng ( ^) an l.


Điều này hoạt động rất tốt, nhưng làm thế nào để chỉ có tên thư mục? Tôi muốn sử dụng cái này trongfor i in
Luka

Bạn có thể giải thích mã này xin vui lòng?
ABG

Coi chừng rằng giải pháp này không hoạt động nếu bạn -ltham gia ls. Vì vậy, điều này sẽ không hoạt động như mong đợi:ls | grep -v ^l
stamster

@Luka Bạn không lặp qua đầu ra của find, xem unix.stackexchange.com/questions/321697
Kusalananda

1
@abg - Tôi đã thêm một lời giải thích. Hy vọng nó giúp.
Geoff

7

Từ phiên bản 2.12 trở đi, -rtùy chọn cho GNU grep không liên kết tượng trưng cho biểu tượng trừ khi bạn chỉ định chúng bằng tay:

-r, - đáng chú ý

Đọc tất cả các tệp trong mỗi thư mục, theo cách đệ quy, chỉ theo các liên kết tượng trưng nếu chúng nằm trên dòng lệnh. Điều này tương đương với tùy chọn -d recurse.

-R, --dereference-đệ quy

Đọc tất cả các tập tin dưới mỗi thư mục, đệ quy. Thực hiện theo tất cả các liên kết tượng trưng, ​​không giống như -r.


Phiên bản nào của grep là vậy. Tôi có -R, -r, --recursive Read all files under each directory, recursively; this is equivalent to the -d recurse option.trong 2.10
TheMeaningfulEngineer

grep (GNU grep) 2.14
tijagi

5

Trong zsh, điều này sẽ dễ dàng nhờ vào vòng loại toàn cầu :

grep -- PATTERN **/*(.)

Các mẫu **/đi qua các thư mục con đệ quy. Vòng loại toàn cầu .hạn chế khớp với các tệp thông thường.

Nếu không có zsh, hãy sử dụng find(xem câu trả lời của Michael Horner ). Và trong trường hợp cụ thể này, GNU grep có thể làm những gì bạn muốn (chính xác là những gì grep -r) - nhưng chỉ từ phiên bản 2.12, các phiên bản trước đó đã tuân theo các liên kết tượng trưng.


2

Bạn có thể sử dụng $LS_COLORSđể làm điều này. Nếu phiên bản lshỗ trợ của bạn chỉ định màu bằng biến đó, bạn có thể xác định đầu ra cho mỗi loại tệp. Đó là hành vi dựng sẵn và rất cấu hình. Vì vậy, tôi đã tạo ra một số tệp để demo như thế này:

for f in 9 8 7 6 5 4 3 2 1
    do touch "${f}file" && 
    ln -s ./"${f}file" ./"${f}filelink"
done

Vì vậy, bây giờ tôi sẽ làm:

LS_COLORS='lc=:rc=:ec=:ln=\n\n\0HERE_THERE_BE_A_LINK>>\0:' \
ls -1 --color=always | cat

###OUTPUT###
1file


HERE_THERE_BE_A_LINK>>1filelink@
2file


HERE_THERE_BE_A_LINK>>2filelink@
3file

...
HERE_THERE_BE_A_LINK>>8filelink@
9file
...

Và null cũng ở đó ...

LS_COLORS='lc=:rc=:ec=:ln=\n\n\0HERE_THERE_BE_A_LINK>>\0:' \
ls -1 --color=always | sed -n l
1file$
$
$
\000HERE_THERE_BE_A_LINK>>\0001filelink@$
2file$
$
$
\000HERE_THERE_BE_A_LINK>>\0002filelink@$
3file$
...

Bạn có thể chỉ định cho tất cả hoặc bất kỳ kiểu tệp nào. Làm như vậy chỉ với một kiểu tệp duy nhất có thể không giúp bạn muốn mặc dù lsđã kết hợp một số giá trị biên dịch mặc định cho các lần thoát cuối. Bạn sẽ làm tốt hơn nhiều để giải quyết api như một giao diện duy nhất. Đây là một phương tiện nhỏ để phân tích cú pháp và gán các dircolorsmặc định được cấu hình của môi trường hiện tại :

LS_COLORS='rs=:no=//:lc=:rc=:ec=//:'$(
set -- di fi ln mh pi so do bd cd or su sg ca tw ow st ex
for fc do printf %s "$fc=/$fc//:"
done) ls -l --color=always | cat

Đầu ra của nó trong thư mục nhà của tôi trông như thế này:

total 884
///-rw-r--r-- 1 mikeserv mikeserv    793 Jul  9 11:23 /fi//1/
//drwxr-xr-x 1 mikeserv mikeserv    574 Jun 24 16:50 /di//Desktop//
//-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 /fi//Terminology.log/
//-rw-r--r-- 1 mikeserv mikeserv      0 Jul  6 11:24 /fi//new
file/
//lrwxrwxrwx 1 mikeserv mikeserv     10 Jul 11 04:18 /ln//new
file
link/ -> /fi//./new
file/
//-rwxr-xr-x 1 mikeserv mikeserv    190 Jun 22 11:26 /ex//script.sh/*
//-rw-r--r-- 1 mikeserv mikeserv 433568 Jun 22 17:10 /fi//shot-2014-06-22_17-10-16.jpg/
//-rw-r--r-- 1 mikeserv mikeserv     68 Jun 17 19:59 /fi//target.txt/

Bạn cũng có thể chạy điều đó cat -Avà sự khác biệt duy nhất bạn sẽ gặp là bạn sẽ thấy $các dòng mới - không có ký tự không thể in được giới thiệu ls --color=alwaysvới cấu hình này - chỉ những gì bạn thấy ở đây.

ls chèn thiết bị đầu cuối mặc định của nó thoát như thế này:

${lc}${type_code}${rc}FILENAME${lc}${rs}${rc}

... Trong đó các giá trị mặc định cho $lc (bên trái mã) , $rc (bên phải mã)$rs (đặt lại) là:

 \033 - ESCAPE
 m - END ESCAPE
 0 - reset 

...tương ứng. ${type_code}được sử dụng để thay thế cho các fi tệp khác nhau (tệp thông thường - không đặt mặc định) , di (thư mục) , ln (liên kết) và mọi loại tệp khác mà tôi biết. Ngoài ra còn có $no (bình thường) cũng là mặc định unset và ở đây được đại diện bởi //ở đầu mỗi dòng. IFS=:Khối nhỏ đơn giản của tôi hoạt động chỉ bằng cách chèn tên cho mỗi cấu hình cũng như giá trị riêng của nó và thêm một dấu gạch chéo hoặc hai - mặc dù các \0byte NUL cũng sẽ làm như vậy.

Theo mặc định lscũng sẽ chèn một cái $rsngay trước đầu ra đầu tiên của nó $lc- nhưng điều này không được trình bày chính xác ở đây. Trong trường hợp này, tôi đã chỉ định $ec (mã kết thúc) đại diện cho $rstất cả các trường hợp - khi được chỉ định, bạn không nhận được thêm $rsgiữa $no${type_code}như bạn muốn - nó chỉ xuất hiện ngay sau tên tệp một lần khi bắt đầu xuất - như bạn có thể thấy trong một dấu gạch chéo ở đầu dòng một.

Đây là một đoạn trích từ riêng tôi $LS_COLORS

printf %s "$LS_COLORS"

rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:\
so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:\
or=40;31;01:su=37;41:sg=30;43:ca=30;41:\
tw=30;42:ow=34;42:st=37;44:ex=01;32:\
*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:...

Và, trong thực tế, hack shell nhỏ của tôi có lẽ quá phức tạp - có một giao diện có sẵn rộng rãi để gán các giá trị này. Hãy thử dircolors -ptrong cli của bạn và info dircolorsđể biết thêm thông tin về điều đó.

Bạn có thể bọc tên tệp theo chuỗi tùy ý. Bạn có thể nhận xét chúng ra nếu bạn muốn. Bạn có thể chỉ định các hành vi tương tự chỉ dựa trên phần mở rộng tệp. Thực sự không có nhiều bạn không thể chỉ định theo cách đó.

Bây giờ tôi cũng không chỉ tạo ra tất cả những điều này - tôi đã tìm hiểu về nó sau khi tình cờ tìm thấy mã nguồn .

Với cấu hình cụ thể này lssẽ phát ra:

  1. $no - một lần cho mỗi bản ghi khi bắt đầu mỗi bản ghi

  2. ${type_code}- một lần ngay trước mỗi tên tệp để bao gồm tên viết tắt của loại tệp và luôn xuất hiện trên cùng một dòng và 7 trường được phân cách bằng khoảng trắng sau $no hoặc ngay sau ->dấu hiệu của mục tiêu liên kết tượng trưng.

  3. $ec - một lần ngay trước dòng đầu tiên và sau đó chỉ một lần ngay sau mỗi tên tệp.

  4. Tất cả các giá trị khác đều trống rỗng.

Những gì tiếp theo là một giới hạn null ls, và lần này tôi sẽ sử dụng cat -A, mặc dù, nếu không có nó, nó sẽ trông giống như ví dụ trước:

LS_COLORS='rs=:no=\0//:lc=:rc=:ec=\0//:'$(
set -- di fi ln mh pi so do bd cd or su sg ca tw ow st ex
for fc do printf %s "$fc=/$fc//\0:"
done) ls -l --color=always | cat -A

total 884$
^@//^@//-rw-r--r-- 1 mikeserv mikeserv    793 Jul  9 11:23 /fi//^@1^@//$
^@//drwxr-xr-x 1 mikeserv mikeserv    574 Jun 24 16:50 /di//^@Desktop^@///$
^@//-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 /fi//^@Terminology.log^@//$
^@//-rw-r--r-- 1 mikeserv mikeserv      0 Jul  6 11:24 /fi//^@new$
file^@//$
^@//lrwxrwxrwx 1 mikeserv mikeserv     10 Jul 11 04:18 /ln//^@new$
file$
link^@// -> /fi//^@./new$
file^@//$
^@//-rwxr-xr-x 1 mikeserv mikeserv    190 Jun 22 11:26 /ex//^@script.sh^@//*$
^@//-rw-r--r-- 1 mikeserv mikeserv 433568 Jun 22 17:10 /fi//^@shot-2014-06-22_17-10-16.jpg^@//$
^@//-rw-r--r-- 1 mikeserv mikeserv     68 Jun 17 19:59 /fi//^@target.txt^@//$

Và vì vậy, để loại bỏ đáng tin cậy tất cả các liên kết tượng trưng khỏi -ldanh sách ong như thế này, bạn có thể thực hiện một thay đổi đơn giản:

LS_COLORS='rs=:no=//:lc=:rc=:ec=/ :'$(
set -- di fi mh pi so do bd cd or su sg ca tw ow st ex
for fc do printf %s "$fc=$fc/:"
done)ln=///: ls -l --color=always | sed ':ln
\|///|{N;\|\n//|!bln};s|.*//||'

Kết quả của tôi sau khi chạy giống như ...

total 884
-rw-r--r-- 1 mikeserv mikeserv    793 Jul  9 11:23 fi/1/ 
drwxr-xr-x 1 mikeserv mikeserv    574 Jun 24 16:50 di/Desktop/ /
-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 fi/Terminology.log/ 
-rw-r--r-- 1 mikeserv mikeserv      0 Jul  6 11:24 fi/new
file/ 
-rwxr-xr-x 1 mikeserv mikeserv    190 Jun 22 11:26 ex/script.sh/ *
-rw-r--r-- 1 mikeserv mikeserv 433568 Jun 22 17:10 fi/shot-2014-06-22_17-10-16.jpg/ 
-rw-r--r-- 1 mikeserv mikeserv     68 Jun 17 19:59 fi/target.txt/ 

Sử dụng một số lệnh như với lệnh tôi làm ở trên:

LSCOLORS=...$(...)fc1=///:fc2=///: ls ... | sed ...

... (nơi fc1fc2là các kiểu tệp được liệt kê sau set --trong lớp con) sẽ phục vụ để loại bỏ đáng kể mọi kết hợp kiểu tệp bạn có thể muốn từ lsđầu ra bất kể ký tự nào có thể chứa tên.


Heh, tốt đẹp, +1 cho độc đáo. Dường như bị nghẹt thở trên các thư mục, chúng được in bằng mã màu ANSI bị cắt xén. Dù sao, bạn có thể thêm một lời giải thích về cách thức này hoạt động? Có lẽ giải thích những gì lc, nc, vv là?
terdon

@terdon - Họ đang chỉ in với ANSI thoát đã được thiết lập trong môi trường của bạn và hoặc biên soạn như là một mặc định cho ls's di=giá trị. Bạn cần thêm di=:vào var để vô hiệu hóa điều đó - và cho tất cả những người khác. Đó là những gì tôi muốn nói với api - bạn giải quyết từng kiểu tệp nhưng bạn phải xử lý giao diện giống nhau trong mọi trường hợp. Vì vậy, thiết lập lnmột cách và bỏ qua dimặc định sẽ không thành công. Có nhiều mặc định được biên dịch trong ... Hmm. Yêu cầu của bạn về lcnccông cụ là hợp lệ - hoàn toàn - tôi đã làm điều đó vào ngày khác. Tôi sẽ liên kết nó, tôi nghĩ.
mikeerv

Ouch, vì vậy tôi phải luôn luôn chỉ định tất cả các loại tệp có thể hoặc kiểm tra những gì hiện diện trước khi xử lý? Được rồi cảm ơn.
terdon

@terdon - hãy xem bản chỉnh sửa của tôi ngay bây giờ - nó thực hiện tất cả trong một vài dòng vỏ, chỉ định từng loại theo tên loại của nó và phân định đáng tin cậy mỗi tên tệp. Không có nonprintables giới thiệu. Và dù sao cũng có một api cho điều đó - nó dircolors. Nó đọc một tập tin cấu hình và xuất ra một evalgiá trị var thân thiện với vỏ . Nó khá dễ dàng - nhưng cũng có vài dòng trên đó. Dù sao, nếu bạn muốn sử dụng, dircolorsbạn chỉ cần lưu hai tệp khác nhau và gọi nó theo cách đó. Ngoài ra, tôi đã chỉ cho bạn một ngày khác làm thế nào để thực hiện cả hai cùng với các \0dấu phân cách NUL như là một phần của mỗi chuỗi thoát.
mikeerv

@terdon - Tôi đã cố gắng làm cho nó rõ ràng hơn dễ dàng như thế nào để thiết lập tất cả các giá trị có thể được biên dịch trong - Tôi nghĩ rằng tôi đã nhận được tất cả, có thể quá nhiều ... LS_COLORS='rs=:no=\0//:lc=:rc=:ec=\0//:'$( set -- di fi ln mh pi so do bd cd or su sg ca tw ow st ex; for fc do printf %s "$fc=/$fc//\0:"; done) ls -l --color=always | cat -A
mikeerv

0

Câu trả lời trên dẫn đến những điều sau đây:

 ls -1F | grep -i "/"

Thật kỳ lạ khi để lại 1 trong số các lệnh ls vẫn đưa ra một danh sách.


1
Tại sao grep -i? Nó không phải như /thể có thể là chữ hoa hoặc chữ thường. lsmặc định ở định dạng cột noe khi đầu ra không phải là thiết bị đầu cuối (đây là một đường ống ở đây).
Kusalananda

-2

Hãy thử cái này:

ls | grep -v " -> "

2
Điều đó sẽ thất bại vì nhiều lý do, ví dụ như trên một tệp được gọi a -> b. Nó cũng sẽ thất bại về tên tập tin với dòng mới và sự kỳ lạ khác. Xin vui lòng đọc này cho lý do tại sao phân tích ls là một ý tưởng tồi.
terdon

@terdon Có nhiều lý do cơ bản hơn tại sao điều này sẽ thất bại. Hoặc lslà bí danh ls -lvà điều này trả về các cột trước tên tệp hoặc không, và điều này không làm gì đặc biệt về các liên kết tượng trưng.
Gilles 'SO- đừng trở nên xấu xa'

@terdon - lsphân tích chính nó. tất cả chúng ta đều phân tích cú pháp lsmỗi khi chúng ta in ra một thiết bị đầu cuối - có một api . Tôi đã đăng một câu trả lời chứng minh một cái gì đó giống như ở đây - nhưng bạn có thể làm nhiều hơn nữa. Tôi đã chỉ cho bạn vào một ngày khác - bạn có tên tập tin được phân định bằng null.
mikeerv

@mikeerv Tôi biết, tôi biết. Tuy nhiên, việc giải thích làm thế nào để thực hiện việc này một cách an toàn mất vài trăm dòng như chính bạn đã chứng minh. Vì thế, câu trả lời này phải chịu đựng tất cả những nguy hiểm của việc phân tích cú pháp và OP rõ ràng không nhận thức được chúng.
terdon

@terdon - lssẽ không ăn con bạn hay bất cứ thứ gì - đó chỉ là một chương trình. Nếu bạn không giải thích thì sẽ mất vài trăm để giải thích hàng trăm câu nữa để giải thích tại sao hàng trăm dòng bạn vừa liên kết là sai. Và bên cạnh đó - đây chỉ là hai dòng:LS_COLORS='lc=:rc=:ec=:ln=\n\n\0HERE_THERE_BE_A_LINK>>\0:' \ ls -1 --color=always | cat
mikeerv

-3

Hãy thử lệnh này: ls -p | grep -v @


Không, liệt kê các liên kết.
TheMeaningfulEngineer

@Alan: k thử cái nàyfind -type f
Do đó,

1
-1 bởi vì: i) Chỉ -pcần thêm một dấu gạch chéo vào các thư mục, bạn đang tìm kiếm -Fii) findthay thế của bạn sẽ không liệt kê các thư mục và iii) Vui lòng kiểm tra câu trả lời của bạn trước khi đăng.
terdon
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.