Liệt kê tất cả các tệp nhị phân từ $ PATH


30

Có một lớp lót sẽ liệt kê tất cả các tệp thực thi từ $ PATH trong bash.

Câu trả lời:


38

Đây không phải là một câu trả lời, nhưng nó hiển thị nhị phân, một lệnh mà bạn có thể chạy

compgen -c

(giả sử bash)

Các lệnh hữu ích khác

compgen -a # will list all the aliases you could run.
compgen -b # will list all the built-ins you could run.
compgen -k # will list all the keywords you could run.
compgen -A function # will list all the functions you could run.
compgen -A function -abck # will list all the above in one go.

1
Thật tốt khi biết lệnh này và tôi thực sự cần các tệp thực thi để hoàn thành. Có lẽ tôi sử dụng lệnh này để thay thế.
jcubic

Lưu ý rằng nó cũng bao gồm các nội dung, hàm, từ khóa (như in, {...) và bí danh.
Stéphane Chazelas

Thưa ông, tôi đã cập nhật .. Tôi đã lưu trong bản nháp của mình, từ lâu tôi đã tìm thấy trên trang này ..
Rahul Patil

@jcubic, shell đã làm điều đó để hoàn thành lệnh Tại sao phải làm bằng tay?
vonbrand

@vonbrand Tôi đang làm việc trên shell trong javascript / php và tôi đang thực thi shell ở chế độ không tương tác.
jcubic

15

Với zsh:

whence -pm '*'

Hoặc là:

print -rl -- $commands

(lưu ý rằng đối với các lệnh xuất hiện trong nhiều thành phần $PATH, chúng sẽ chỉ liệt kê phần đầu tiên).

Nếu bạn muốn các lệnh không có đường dẫn đầy đủ và được sắp xếp theo số đo tốt:

print -rl -- ${(ko)commands}

(nghĩa là lấy các khóa của mảng kết hợp đó thay vì các giá trị).


Tôi đã không đề cập rằng tôi đang sử dụng bash.
jcubic

5

Trong bất kỳ shell POSIX nào, không sử dụng bất kỳ lệnh bên ngoài nào (giả sử đã printfđược tích hợp sẵn, nếu không rơi trở lại echo) ngoại trừ việc sắp xếp cuối cùng và giả sử rằng không có tên thực thi nào có chứa một dòng mới:

{ set -f; IFS=:; for d in $PATH; do set +f; [ -n "$d" ] || d=.; for f in "$d"/.[!.]* "$d"/..?* "$d"/*; do [ -f "$f" ] && [ -x "$f" ] && printf '%s\n' "${x##*/}"; done; done; } | sort

Nếu bạn không có thành phần trống trong $PATH(sử dụng .thay thế) cũng như các thành phần bắt đầu bằng -, cũng không phải ký tự đại diện \[?*trong các thành phần PATH hoặc tên thực thi và không có tệp thực thi nào bắt đầu bằng ., bạn có thể đơn giản hóa điều này thành:

{ IFS=:; for d in $PATH; do for f in $d/*; do [ -f $f ] && [ -x $f ] && echo ${x##*/}; done; done; } | sort

Sử dụng POSIX findsed:

{ IFS=:; set -f; find -H $PATH -prune -type f -perm -100 -print; } | sed 's!.*/!!' | sort

Nếu bạn sẵn sàng liệt kê tệp không thể thực thi hiếm hoặc tệp không thường xuyên trong đường dẫn, có một cách đơn giản hơn nhiều:

{ IFS=:; ls -H $PATH; } | sort

Điều này bỏ qua các tập tin dấu chấm; nếu bạn cần chúng, hãy thêm -Acờ vào lsnếu bạn có nó hoặc nếu bạn muốn gắn bó với POSIX:ls -aH $PATH | grep -Fxv -e . -e ..

Có các giải pháp đơn giản hơn trong bashtrong zsh .


Giả định rằng nó $PATHđược đặt và không chứa các thành phần trống và các thành phần đó trông không giống như tìm các vị từ (hoặc tùy chọn ls). Một số trong số đó cũng sẽ bỏ qua các tập tin dấu chấm.
Stéphane Chazelas

@StephaneChazelas Vâng, ok. Ngoài các thành phần trống rỗng, phần này nằm trong nhóm không thực hiện thể loại này - PATH nằm dưới sự kiểm soát của bạn.
Gilles 'SO- ngừng trở nên xấu xa'

Nó vẫn không hoạt động nếu phần tử trống là cuối cùng (như thường lệ). (ngoại trừ trong yashzshtrong thi đua sh).
Stéphane Chazelas

Trong findmột của bạn . -prunesẽ ngăn chặn danh sách thư mục. Bạn có thể muốn -Lthay vì -Hnhư bạn muốn bao gồm các liên kết tượng trưng (phổ biến cho các tệp thực thi). -perm -100không đảm bảo rằng tệp có thể được thực thi bởi bạn (và có thể (không thể) loại trừ các tệp thực thi).
Stéphane Chazelas

4

Tôi nghĩ ra cái này:

IFS=':';for i in $PATH; do test -d "$i" && find "$i" -maxdepth 1 -executable -type f -exec basename {} \;; done

EDIT : Có vẻ như đây là lệnh duy nhất không kích hoạt cảnh báo SELinux trong khi đọc một số tệp trong thư mục bin của người dùng apache.


5
Tại sao for? IFS=:; find $PATH -maxdepth 1 -executable -type f -printf '%f\n'
manatwork 21/03 '

@manatwork nó sẽ làm việc cho các đường dẫn không tồn tại?
jcubic

@manatwork không biết rằng bạn có thể làm điều đó. cần đọc thêm về IFS.
jcubic

3
Giả định rằng nó $PATHđược đặt và không chứa các ký tự đại diện và không chứa các thành phần trống. Điều đó cũng giả định việc thực hiện GNU find.
Stéphane Chazelas

2
Bởi vì -type fthay vì (GNU cụ thể) -xtype f, điều đó cũng sẽ bỏ qua các liên kết tượng trưng. Điều đó cũng sẽ không liệt kê nội dung của các $PATHthành phần là liên kết tượng trưng.
Stéphane Chazelas

3

Còn cái này thì sao

find ${PATH//:/ } -maxdepth 1 -executable

Sự thay thế chuỗi được sử dụng với Bash.


3
Giả sử đã $PATHđược đặt, không chứa ký tự đại diện hoặc ký tự trống, không chứa các thành phần trống. Điều đó giả định GNU cũng tìm thấy. Lưu ý đó ${var//x/y}kshcú pháp (cũng được hỗ trợ bởi zsh và bash). Nói đúng ra cũng cho rằng các thành phần $ PATH cũng không phải là findvị ngữ.
Stéphane Chazelas

1
Điều đó cũng cho rằng $PATHcác thành phần không phải là liên kết tượng trưng.
Stéphane Chazelas

@StephaneChazelas: Cảm ơn! Nói cách khác, trường hợp thông thường.

Cài đặt IFS=:mạnh mẽ hơn so với thực hiện thay thế này. Đường dẫn có dấu cách không phổ biến trên Windows. Liên kết tượng trưng là khá phổ biến, nhưng điều đó dễ dàng được giải quyết -H.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles: tất nhiên rồi. tuy nhiên tôi không thấy bất kỳ trường hợp sử dụng hợp lý nào cho câu hỏi này, do đó không cần câu trả lời chống đạn.

1

Nếu bạn có thể chạy python trong shell của mình, thì một lớp lót sau (dài một cách lố bịch) cũng có thể được sử dụng:

python -c 'import os;import sys;output = lambda(x) : sys.stdout.write(x + "\n"); paths = os.environ["PATH"].split(":") ; listdir = lambda(p) : os.listdir(p) if os.path.isdir(p) else [ ] ; isfile = lambda(x) : True if os.path.isfile(os.path.join(x[0],x[1])) else False ; isexe = lambda(x) : True if os.access(os.path.join(x[0],x[1]), os.X_OK) else False ; map(output,[ os.path.join(p,f) for p in paths for f in listdir(p) if isfile((p,f)) and isexe((p,f)) ])'

Đây chủ yếu là một bài tập thú vị cho bản thân tôi để xem liệu nó có thể được thực hiện bằng cách sử dụng một dòng mã trăn mà không cần sử dụng chức năng 'exec' hay không. Ở dạng dễ đọc hơn và với một số bình luận, mã trông như thế này:

import os
import sys

# This is just to have a function to output something on the screen.
# I'm using python 2.7 in which 'print' is not a function and cannot
# be used in the 'map' function.
output = lambda(x) : sys.stdout.write(x + "\n")

# Get a list of the components in the PATH environment variable. Will
# abort the program is PATH doesn't exist
paths = os.environ["PATH"].split(":")

# os.listdir raises an error is something is not a path so I'm creating
# a small function that only executes it if 'p' is a directory
listdir = lambda(p) : os.listdir(p) if os.path.isdir(p) else [ ]

# Checks if the path specified by x[0] and x[1] is a file
isfile = lambda(x) : True if os.path.isfile(os.path.join(x[0],x[1])) else False

# Checks if the path specified by x[0] and x[1] has the executable flag set
isexe = lambda(x) : True if os.access(os.path.join(x[0],x[1]), os.X_OK) else False

# Here, I'm using a list comprehension to build a list of all executable files
# in the PATH, and abusing the map function to write every name in the resulting
# list to the screen.
map(output, [ os.path.join(p,f) for p in paths for f in listdir(p) if isfile((p,f)) and isexe((p,f)) ])

0
#!/usr/bin/env python
import os
from os.path import expanduser, isdir, join, pathsep

def list_executables():
    paths = os.environ["PATH"].split(pathsep)
    executables = []
    for path in filter(isdir, paths):
        for file_ in os.listdir(path):
            if os.access(join(path, file_), os.X_OK):
                executables.append(file_)
    return executables
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.