PATH'de bir programın tam yolunu nasıl güvenilir bir şekilde bulabilirim?


12

PATHBir kabuk komut dosyası kullanarak belirli bir programın yolunu bulmam gerekiyor . Yol, daha sonra kendisini aramayan exec*işlevlerden birine geçirilebilen programın gerçek tam yolu olmalıdır PATH, örn execv.

Aynı anda killgerçek bir program ve yerleşik bir kabuk olarak kullanılabilen programlar vardır . Bu durumda, gerçek programın tam yoluna ihtiyacım var.

POSIX standardının Bölüm 2.9.1.1, Komut Arama ve Yürütme bölümündePATH belirtildiği gibi bir program bulabilen birkaç yardımcı program vardır .

Orada whichherhangi bir standardın parçası olmadığı,. Bazı sistemlerde düzenli bir program olabilirken, bazı kabuklar yerleşiktir. Çoğu sistemde ve kabukta kullanılabilir gibi görünüyor, ancak yerleşik bir versiyona sahip kabuklar, çalıştırılabilir yolun yolu yerine yerleşik olanın adını da döndürüyor. Ayrıca herhangi bir şekilde standartlaştırılmamıştır ve herhangi bir çıktıyı iade edebilir ve farklı seçenekler alabilir.

bash# which kill
/usr/bin/kill
dash# which kill
/usr/bin/kill
fish# which kill
/usr/bin/kill
mksh# which kill
/usr/bin/kill
tcsh# which kill
kill: shell built-in command.
zsh# which kill
kill: shell built-in command

Orada whencehangi bir yerleşik bir kaç kabukları. Ama pek çok mermide mevcut değil. Programlama yolu yerine yerleşik adı da döndürür. -pBu davranışı değiştirmek için A'ya geçilebilir.

bash# whence kill
bash: whence: command not found
dash# whence kill
dash: 1: whence: not found
fish# whence kill
fish: Unknown command 'whence'
mksh# whence kill
kill
mksh# whence -p kill
/usr/bin/kill
tcsh# whence kill
whence: Command not found.
zsh# whence kill
kill
zsh# whence -p kill
/usr/bin/kill

commandPOSIX: 2008 tarafından belirtilen yerleşik yapı vardır . Ne yazık ki normal komutları ve yerleşikleri de arar ve aynı adda yerleşik bir programın gölgelediği programın yolu yerine yerleşik adını döndürür. Bazı eski mermiler henüz uygulanmadı.

bash# command -v kill
kill
dash# command -v kill
kill
fish# command -v kill
/usr/bin/kill
mksh# command -v kill
kill
tcsh# command -v kill
command: Command not found.
zsh# command -v kill
kill

Eğer çözemiyorum enablePOSIX'deki veya belirtilmedi, ancak eğer şunu kullanabilirsiniz enable -n whichyerleşik için kabuk devre dışı bırakmak için which.
Muzer

ve oradarealpath
Ipor Sircer

@Muzer Elimdeki kabuklarda enable, sadece bashve tarafından sağlanırzsh
Sebastian Schrader

2
Komut dosyanızı çalıştıran belirli kabuk için tüm kabuklar için değil , okunabilir bir yönteme ihtiyacınız vardır . Komut dosyaları rastgele bir kabuk tarafından değil, özellikle shebang satırında belirtilen kabuk tarafından yürütülür. Olduğu söyleniyor, bash içinde olurdu type -p. Hem bash hem de dash command, aynı ada sahip bir işlev veya yerleşik olsa bile, gerçek bir yürütülebilir dosyayı çalıştırma komutunu söylemenizi sağlar .
AlexP

1
@AlexP, commandfonksiyonların (ve takma adların) atlamasına rağmen Q'nun doğru söylediği gibi yerleşmez . Ve her zaman bir shebang kullanamazsınız çünkü tüm sistemlerde herhangi bir kabuk, hatta bir POSIX kabuğu alan bir yol yoktur.
dave_thompson_085

Yanıtlar:


11

Sadece kendiniz arayın.

export IFS=":"
[ -z "${1}" ] && exit 1
for dir in $PATH
do if [ -x "${dir}/${1}" ]
   then echo "${dir}/${1}"
        exit 0
   fi
done
echo ${1} not found
exit 1

Test edilmiştir bash, dash, ksh, mksh,zsh

Güncelleme

Yukarıdakiler tek başına bir komut dosyası için güzeldir, ancak bunu daha büyük bir komut dosyasına yerleştirmeyi planlıyorsanız, aşağıdakine benzer bir şey kullanmak isteyebilirsiniz.

function find_path() {
   IFS_SAVE="${IFS}"
   export IFS=":"
   [ -z "${1}" ] && return 1
   for dir in $PATH
   do if [ -x "${dir}/${1}" ]
      then echo "${dir}/${1}"
           export IFS="${IFS_SAVE}"
           return 0
      fi
   done
   export IFS="${IFS_SAVE}"
   echo ${1} not found
   return 1
}

Bunun sebebi IFSmaçı da Takaslanan bulduktan sonra geri exit'ın birlikte return' ler


1
Belki -f yerine -x?
Jeff Schaller

@JeffSchaller iyi bir nokta, yürütülebilir olmayan dosyaları seçmek için bir neden yok.
Zachary Brady

3
Bunu daha büyük bir kabuk komut dosyasına entegre ederseniz (tahmin edildiği gibi, kendi başına bir komut dosyasına dönüştürmek yerine), IFS'nin eski değerini daha sonra geri yüklemek isteyebilirsiniz - aksi takdirde, bunun üzerinde çok fazla etkisi olabilir. senaryonun geri kalanı ...
psmears

IFSDeğişkeni neden dışa aktarmalıyım? Bunu yerel kabuğa koymak yeterli değil mi? Yerel konuşma, local IFStaşınabilir olurdu ? Başka bir şey IFS'yi aynı şekilde kaydediyorsa, yukarıdakiler kötü etkileşime girebilir. Baktığımızda SE bu soruya , localPOSIX olmama rağmen çoğu kabukları çalışabilir. Orijinal sürümü (…)alt kabuğa koymak da işe yarayabilir.
MvG
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.