Daftar semua binari dari $ PATH

30

Apakah ada satu-liner yang akan mencantumkan semua executable dari $ PATH di bash.

jcubic
sumber

Jawaban:

38

Ini bukan jawaban, tetapi ini menunjukkan biner, perintah yang bisa Anda jalankan

compgen -c

(dengan asumsi bash)

Perintah lain yang bermanfaat

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.
Rahul Patil
sumber
1
Senang mengetahui perintah ini, dan saya benar-benar membutuhkan executable untuk diselesaikan. Mungkin saya menggunakan perintah ini sebagai gantinya.
jcubic
Perhatikan bahwa itu juga mencakup builtin, fungsi, kata kunci (seperti in, {...) dan alias.
Stéphane Chazelas
Pak, saya telah memperbarui .. Saya telah menyimpan dalam konsep saya, pada waktu yang lama saya temukan di situs ini ..
Rahul Patil
@ jcubic, shell sudah melakukannya untuk menyelesaikan perintah. Mengapa melakukannya dengan tangan?
vonbrand
@vonbrand saya sedang mengerjakan shell dalam javascript / php dan saya mengeksekusi shell dalam mode non interaktif.
jcubic
15

Dengan zsh:

whence -pm '*'

Atau:

print -rl -- $commands

(perhatikan bahwa untuk perintah yang muncul di lebih dari satu komponen $PATH, mereka akan mendaftar hanya yang pertama).

Jika Anda ingin perintah tanpa jalur lengkap, dan diurutkan untuk mengukur:

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

(Yaitu, dapatkan kunci array asosiatif alih-alih nilai).

Stéphane Chazelas
sumber
Saya tidak menyebutkan bahwa saya menggunakan bash.
jcubic
5

Dalam setiap shell POSIX, tanpa menggunakan perintah eksternal (dengan asumsi printfdibangun di dalam, jika tidak kembali ke echo) kecuali untuk pengurutan akhir, dan dengan asumsi bahwa tidak ada nama yang dapat dieksekusi berisi baris baru:

{ 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

Jika Anda tidak memiliki komponen kosong dalam $PATH(gunakan .saja) atau komponen yang dimulai dengan -, atau karakter wildcard \[?*dalam komponen PATH atau nama yang dapat dieksekusi, dan tidak ada yang dapat dijalankan yang dimulai dengan ., Anda dapat menyederhanakan ini ke:

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

Menggunakan POSIX finddan sed:

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

Jika Anda bersedia untuk mencantumkan file langka yang tidak dapat dieksekusi atau file tidak biasa di jalur, ada cara yang lebih sederhana:

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

Ini melompati file dot; jika Anda membutuhkannya, tambahkan -Abendera ke lsjika Anda memilikinya, atau jika Anda ingin tetap berpegang pada POSIX:ls -aH $PATH | grep -Fxv -e . -e ..

Ada solusi yang lebih sederhana di bash dan di zsh .

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Itu mengasumsikan bahwa $PATHdiatur dan tidak mengandung komponen kosong, dan bahwa komponen tidak terlihat seperti menemukan predikat (atau opsi ls). Beberapa dari mereka juga akan mengabaikan file dot.
Stéphane Chazelas
@StephaneChazelas Ya, ok. Terlepas dari komponen kosong, ini jatuh tepat di bawah kategori "jangan lakukan ini" - PATH berada di bawah kendali Anda.
Gilles 'SANGAT berhenti menjadi jahat'
Itu masih tidak berfungsi jika elemen kosong adalah yang terakhir (seperti biasanya). (Kecuali dalam yashdan zshdalam emulasi sh).
Stéphane Chazelas
Di findsatu Anda . -pruneakan mencegah daftar direktori. Anda mungkin ingin -Lbukan -Hkarena Anda ingin menyertakan symlink (umum untuk executable). -perm -100tidak memberikan jaminan bahwa file dapat dieksekusi oleh Anda (dan mungkin (tidak mungkin) mengecualikan file yang dapat dieksekusi).
Stéphane Chazelas
4

Saya datang dengan ini:

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

EDIT : Tampaknya ini adalah satu-satunya perintah yang tidak memicu peringatan SELinux saat membaca beberapa file di direktori bin oleh pengguna apache.

jcubic
sumber
5
Mengapa for? IFS=:; find $PATH -maxdepth 1 -executable -type f -printf '%f\n'
manatwork
@manatwork apakah ini akan berfungsi untuk jalur yang tidak ada?
jcubic
@Manatwork tidak tahu Anda bisa melakukannya. perlu membaca lebih lanjut tentang IFS.
jcubic
3
Itu mengasumsikan bahwa $PATHdiatur dan tidak mengandung karakter wildcard dan tidak mengandung komponen kosong. Itu juga mengasumsikan implementasi GNU dari find.
Stéphane Chazelas
2
Karena -type falih - alih (khusus GNU) -xtype f, itu juga akan menghilangkan symlink. Itu juga tidak akan mencantumkan konten $PATHkomponen yang merupakan symlink.
Stéphane Chazelas
3

Bagaimana dengan ini

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

Substitusi string digunakan dengan Bash.


sumber
3
Itu mengasumsikan bahwa $PATHdiatur, tidak mengandung karakter pengganti atau karakter kosong, tidak mengandung komponen kosong. Itu mengasumsikan menemukan GNU juga. Perhatikan bahwa ${var//x/y}ini adalah kshsintaks (juga didukung oleh zsh dan bash). Tegasnya, itu juga mengasumsikan bahwa komponen $ PATH juga bukan findpredikat.
Stéphane Chazelas
1
Itu juga mengasumsikan bahwa $PATHkomponen bukanlah symlink.
Stéphane Chazelas
@StephaneChazelas: Terima kasih! Dengan kata lain, kasus biasa.
Pengaturan IFS=:lebih kuat daripada melakukan substitusi ini. Jalur dengan spasi tidak biasa di Windows. Tautan simbolik cukup umum, tetapi mudah dipecahkan -H.
Gilles 'SANGAT berhenti menjadi jahat'
@Gilles: tentu saja. namun saya tidak melihat adanya use-case yang masuk akal untuk pertanyaan ini, oleh karena itu tidak perlu jawaban yang anti peluru.
1

Jika Anda dapat menjalankan python di shell Anda, maka satu-liner berikut (panjangnya ridiculously) dapat digunakan juga:

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)) ])'

Ini sebagian besar merupakan latihan yang menyenangkan bagi saya untuk melihat apakah itu dapat dilakukan dengan menggunakan satu baris kode python tanpa menggunakan fungsi 'exec'. Dalam bentuk yang lebih mudah dibaca, dan dengan beberapa komentar, kode ini terlihat seperti ini:

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)) ])
brm
sumber
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
Steven
sumber