Daftar semua file / binari di PATH saat ini

10

Apakah ada cara "mudah" untuk menjalankan perintah gaya "ls -la" untuk membuat daftar semua file / binari yang dapat dieksekusi di PATH saat ini?

(Saya bermaksud untuk menyalurkan output ke grep, untuk mencari perintah dengan awalan yang tidak diketahui tetapi pada dasarnya dikenal "nama", jenis kasus ketika pelengkapan / tab otomatis di bash pada dasarnya tidak berguna. Jadi semacam "inversi otomatis" fitur lengkap "...)

sme
sumber
Bisakah Anda memberi contoh? Bagaimana bedanya dengan ls -la?
John Siu
"ls -la" / "ls -a" hanya menampilkan file di direktori Anda saat ini (pwd). Saya ingin mendaftar semua file (dapat dieksekusi) di semua direktori yang termasuk dalam PATH.
sme

Jawaban:

19
compgen -c # will list all the commands you could run.
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. 
Nykakin
sumber
Bagus, ini sangat banyak yang saya cari. Bahkan termasuk binari yang dapat dieksekusi di direktori saat ini. Terima kasih.
sme
Bekerja dengan baik ... dalam bash.
Emanuel Berg
Adakah cara untuk membuat daftar jalan masing-masing tanpa melakukan which $(compgen -A function -abck)?
h3rrmiller
Saya tidak dapat menemukan alternatif yang lebih baik.
Nykakin
3

Berikut adalah fungsi yang mencantumkan konten direktori $PATH. Jika melewati argumen, fungsi hanya mencantumkan perintah yang namanya mengandung salah satu argumen. Argumen diinterpretasikan sebagai pola glob.

shopt -s extglob
lspath () {
  local IFS pattern
  IFS='|'
  pattern="*@($*)*"
  IFS=':'
  for d in $PATH; do
    for x in "$d/"$pattern; do
      [ "$x" = "$d/$pattern" ] || echo "${x##*/}"
    done
  done | sort -u
}

Seperti banyak hal, ini lebih mudah di zsh.

lspath () {
  (($#)) || set ''
  print -lr -- $^path/*$^@*(N:t) | sort -u
}

The ^karakter dalam ekspansi parameter menyebabkan teks bersambung dengan array yang akan ditambahkan ke setiap elemen array, misalnya path=(/bin /usr/bin); echo $^path/foocetakan /bin/foo /usr/bin/foo.
/*$^@*terlihat seperti penghinaan buku komik tetapi sebenarnya karakter biasa /, wildcard *, parameter khusus $@(array parameter posisi) dengan ^pengubah, dan lagi *.
(N:t)adalah kualifikasi glob N untuk mendapatkan ekspansi kosong jika tidak ada pertandingan yang diikuti oleh pengubah sejarah t untuk menjaga hanya nama belakang ("ekor") dari setiap pertandingan.

Lebih samar, menghindari panggilan eksternal tetapi ini hanya untuk kepentingan kosmetik:

lspath () {
  (($#)) || set ''
  local names; names=($^path/*$^@*(N:t))
  print -lr -- ${(ou)names}
}

Anda mungkin sebenarnya sedang mencari aproposperintah, yang mencari halaman manual dari perintah yang deskripsi singkatnya berisi kata kunci. Batasannya adalah ini hanya menemukan perintah yang memiliki halaman manual.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Dalam fungsi zsh, yang kedua ^tampaknya tidak menghasilkan keluaran untuk panggilan "tanpa argumen"? Jika Anda menjatuhkannya, Anda bisa mendaftar semuanya, dan masih mencari kata kunci tunggal (tetapi bukan daftar kata kunci). The (Non:t)tampaknya mengatakan bahwa tanda bintang harus diperluas? Tidak dapat menemukan yang terakhir.
Emanuel Berg
@ EmanuelBerg Benar, terima kasih atas perbaikannya. Saya telah menambahkan penjelasan tentang garis kebisingan.
Gilles 'SANGAT berhenti menjadi jahat'
OK, mari kita lihat: Jika tidak ada argumen, Anda menetapkan "mereka" untuk apa-apa, karena apa yang ada di sana (ketika tidak ada), entah bagaimana masih mengganggu apa yang Anda lakukan selanjutnya? Juga, saya belum pernah melihat huruf kecil path, tetapi ketika saya menjalankannya di shell, itu memang $ PATH tetapi dengan spasi bukan :. Selebihnya jernih :)
Emanuel Berg
@ EmanuelBerg No: jika tidak ada argumen, saya mengatur array argumen menjadi array satu elemen yang berisi string kosong. Dengan cara ini, tidak ada argumen yang berarti setiap nama yang berisi string kosong cocok, yaitu setiap nama cocok. $pathadalah fitur zsh: ini adalah parameter terikat , array yang diperbarui secara otomatis saat PATHdiperbarui dan sebaliknya.
Gilles 'SO- stop being evil'
Aha, sekarang saya mengerti! Wow, itu tidak lazim!
Emanuel Berg
1
function findinpath () { 
   OLDIFS="$IFS" ; 
   IFS="$(printf ':\t\n')" ; 
   for regexp in "$@" ; do 
      for adir in $PATH ; do 
         find "$adir" -perm -111 -a ! -type d -ls 2>/dev/null | grep -i "/[^/]*$regexp"
      done ; 
   done ; 
   IFS="$OLDIFS" ; 
}

find hanya cocok dengan itu: memiliki setidaknya satu set bit "x" (dapat dieksekusi), dan itu bukan direktori.

dan gunakan dengan daftar regexp untuk ditemukan:

findinpath awk sed '\.sh$'
Olivier Dulac
sumber
regexp "." akan menunjukkan semuanya
Olivier Dulac
dengan IFS reguler, Anda dapat menemukan entri duplikat di $ PATH Anda dengan:echo $PATH | tr ':' '\n' | sort | uniq -d
Olivier Dulac
1
Saya mencoba kode untuk semua jawaban dan ini adalah satu-satunya yang benar-benar memberi saya apa yang saya cari (path lengkap ke setiap instance dari perintah yang diberikan pada PATH).
Chris Page
Saya senang itu membantu :)
Olivier Dulac
1
for i in $(echo $PATH | sed -e 's/\:/\ /g'); do find "$i" -perm +rwx -exec echo {} \; 2> /dev/null; done

pertama kita gema $PATHke sed dan ganti ":" dengan "".

kemudian kami mencari pada masing-masing hal untuk menemukan file dengan rwx dan menggemakannya.

2> /dev/nullbegitu findtidak akan mencetak kesalahan

h3rrmiller
sumber
3
Anda memerlukan -maxdepth 1dan -type fdalam pencarian Anda, kalau tidak Anda akan menemukan subdirektori dan file-file mereka (yang pencarian PATH tidak akan). Juga, tes izin Anda aneh — haruskah hanya untuk +x, kurasa?
derobert
Ini tidak akan menangani kasus tepi jika entri kosong yang valid sama dengan '.', Misalnya :/binatau /bin::/usr/bin. Coba tambahkan s/::/:.:/;s/^:/.:/;s/:$/:./ke sedperintah.
Arcege
Sebenarnya finddapat mencari lebih banyak jalur, sehingga Anda dapat melakukannya tanpa loop: find $(echo $PATH | sed -e 's/\:/\ /g') -perm +rwx …Tentu saja, nama direktori yang mengandung spasi akan mengacaukannya, tetapi yang berbasis loop memiliki masalah yang sama.
manatwork
@manatwork kamu benar. Saya menambahkan kutipan untuk mengatasi masalah itu sekarang
h3rrmiller
Maaf, itu tidak menyelesaikan apa pun. Masalahnya adalah dengan mengganti titik dua dengan spasi untuk memungkinkan pemisahan kata. Jadi Anda mengubah "/ foo bar: / fiz baz" menjadi "/ foo bar / fiz baz" lalu meneruskannya ke for. Jadi forakan mengulang daftar 4 kata. Untuk memanipulasi kata membelah lebih baik mengatur IFSsesuai dengan kebutuhan Anda: IFS=':'; find $PATH -perm +rwx ….
manatwork