skriptning bir xil nomi bilan PATH da buyruqni qidirish

Masalan, mening kodim $ HOME/bin/sudo . $ PATH da bir xil nomdagi sudo bilan ishlaydigan dasturni qidirmoqchiman va uni ishga tushirishni istayman, lekin kod $ HOME/bin/sudo o'zi, aks holda men cheksiz pastadirga o'taman!

E'TIRONING: bu nuqta, ayrim hollarda almashtirish buyruqlarining muntazam tizim buyruqlariga ustunlik berishini xohlayman, ba'zi hollarda esa buning teskarisini istayman. Shuning uchun men PATHda birinchi bo'lib "$ HOME/bin" ni o'rnatdim, shuning uchun endi har bir buyruqlar uchun alohida-alohida belgilashingiz mumkin. Bundan tashqari, bir nechta "portativlik" istayman, shuning uchun scripts turli tizimlarda ishlashi mumkin bo'ladi.

3
Siz aslida nima qilishga harakat qilyapsiz? Menga XY muammoni o'xshaydi.
qo'shib qo'ydi muallif luiscubal, manba
Yo'q, men tizim buyrug'iga muqobil sifatida ishlaydigan buyruqni yozishni istayman, lekin tizim buyrug'i mavjud bo'lmasa ... Menimcha, aniq skript holda, tizim buyrug'ini bekor qilishi mumkin ...
qo'shib qo'ydi muallif Reshma, manba
Men sizning savolingizni to'liq tushunmayapman - $ HOME/bin-da joylashgan skriptingiz bor va uni $ PATH-dagi bir papkaga qo'ygansiz va endi siz qaerdan bilasiz?
qo'shib qo'ydi muallif ciuciu, manba

6 javoblar

Buyruqlar yoki funksiyalarga ehtiyoj yo'q. Agar siz oddiygina $ HOME/bin ni yo'lingizdan kiritgan bo'lsangiz, u faqat $ PATH katalogidagi avvalgi kataloglarda mos keladigan buyruqlar nomi bo'lmasa ishlatiladi.

Misol:

[[email protected] ~]$ export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
[[email protected] ~]$ which foo
/usr/bin/which: no foo in (/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin)
[[email protected] ~]$ export PATH=$PATH:$HOME/bin
[[email protected] ~]$ which foo
~/bin/foo
[[email protected] ~]$ sudo cp bin/foo  /usr/local/bin/
[[email protected] ~]$ which foo
/usr/local/bin/foo

If you don't trust that you can set your own $PATH, so that you still want to do the check from within the script, here's an Misol:

#!/bin/bash
export ORIGPATH=$PATH  # to revert the path after checking for the binary
export PATH=`echo $PATH |sed -e 's{/home/jenny/bin:{{'`

MYNAME=`basename $0`

if  which $MYNAME
then
    BINFILE=`which $MYNAME`
    export PATH=$ORIGPATH 
    echo "Found $MYNAME in $BINFILE "
    $BINFILE
else
    export PATH=$ORIGPATH
    echo "Here goes the rest of the script"
fi
4
qo'shib qo'ydi
~/bin ni kiritish oxirgi marta bu erda ishlamaydi, chunki original buyrug'ning dastlabki bajarilishini, dastlabki saralash buyrug'i o'rniga mo'ljallangan tarzda amalga oshiradi.
qo'shib qo'ydi muallif Valters Vingolds, manba
Bu juda yaxshi gap. Men bu javobdan voz kechishni istamadim - bu juda yaxshi va men yozganimdan ancha oldin ovozim bor edi. $ PATH usurping orqali ishlaydigan terminali chiqishni ranglantirish uchun ruby ​​ skriptlari bilan uzoq vaqt oldin darsni o'rgandim. kompilyatsiya qilinganlar dahshatli . faqat yaxshi buyruq -p getconf PATH har kimni sizni muharrir yoki ikkita qabul qilish uchun ishonishingiz mumkin.
qo'shib qo'ydi muallif Bill Comer, manba
Agar siz $ PATH ga ishonmasangiz buyruqni -p getconf PATH
qo'shib qo'ydi muallif Bill Comer, manba
@Gilles Menimcha, bizlardan biri bu muammoni noto'g'ri tushungan, chunki bu savol menga savolning qanday shakllantirilganidan mantiqiy emas.
qo'shib qo'ydi muallif Jenny D, manba
@eadmaster Ba'zan siz o'zingizning muhitingizni o'zingiz xohlagan tarzda o'rnatishingiz uchun mas'uliyatni zimmasiga olishingiz kerak. Bir nechta yozuvlar bilan shug'ullanish oson; man sed sizga qanday qilib tuzatish kerakligini aytadi. Symlinks - bundan ham oson, hali ham mumkin. Ammo, boshidan aytib o'tganimdek, siz $ PATH ning ma'lum bir usulini ko'rishini istasangiz, uni o'zingiz (avvalo profilingiz/ .bashrc ) joylashtirishingiz kerak va shunchaki ma'no.
qo'shib qo'ydi muallif Jenny D, manba
@eadmaster Buning uchun tuzatildi.
qo'shib qo'ydi muallif Jenny D, manba
@eadmaster kod snippet qo'shildi. ( \ kodini yozib olishni istamasligim uchun { ni ajratuvchi sifatida foydalanganman)
qo'shib qo'ydi muallif Jenny D, manba
Qidiruv tartibi standartlashtirilgan. O'zingizning yo'lingizni belgilashingiz mumkin, chunki uni $ HOME/bin oxirgi bo'lishi mumkin. Yoki bu maxsus skriptlarni boshqa katalogga (masalan, $ HOME/scripts ) joylashtirishingiz mumkin va u katalogni sizning yo'lingizga qo'shishingiz mumkin.
qo'shib qo'ydi muallif Jenny D, manba
bu yechimning yonma ta'siri "$ MYNAME" ham o'zgartirilgan $ PATH bilan ishlaydi ...
qo'shib qo'ydi muallif Reshma, manba
OK, lekin men bu yoki ba'zi tizim skriptlarini $ PATH o'zgaruvchini o'zgartirishni unutgan bo'lsam ham, aniqroq tekshirishni afzal ko'rmoqdaman ...
qo'shib qo'ydi muallif Reshma, manba
boshqa muammo shundaki, $ PATH da "$ HOME/bin" ning bir nechta yozuvlari bo'lishi mumkin, ularning ba'zilari sembolik bo'lishi mumkin (mening "$ HOME/my-applications/bin" HOME/ming "). Ya'ni, $ PATH ni taklif qilib, asl holatini tiklash yana bir yechim bo'lishi mumkin.
qo'shib qo'ydi muallif Reshma, manba
OK, lekin "$ HOME/bin" $ PATH-da joylashgan varsayımları qila olmayman. Shuningdek, $ PATH qidirish tartibi standartlashtirilgan emas.
qo'shib qo'ydi muallif Reshma, manba

POSIX -p parametrini buyrug'i uchun joylashtirilgan deb belgilaydi ...

  • -p Perform the command search using a default value for PATH that is guaranteed to find all of the standard utilities.

buyrug'i bilan bog'liq (mos ravishda) chiqishi uchun -v va -V > Joylashuvni va sizdan biriga so'raganingizda sizga mo'ljallangan dasturni olish uchun juda yaxshi tayanilasiz. Qanday ishlaydi demo uchun kichik bir buyruq fayli:

(   cd ~; mkdir -p bin
    cat >./bin/cat
    chmod +x ./bin/cat
    export "PATH=$HOME/bin:$PATH"
    command -V cat | cat
) <<\NOTCAT
#!/bin/sh
command -p cat
! printf "I'm not REALLY cat, but '%s' is!\n" \
         "$(command -pv cat)"
NOTCAT

OUTPUT

cat is /home/mikeserv/bin/cat
I'm not REALLY cat, but '/bin/cat' is!

Birinchi juftlik so'zlari ~/bin/mushukning bajariladigan buyrug'i hosil qiladi. $ PATH , shuningdek, boshida ~/bin ni qo'shish uchun o'zgartirildi.

Shuning uchun men buyrug'i -V cat | ni qilganda cat buyrug'i mening soxta cat stdin fayliga yozadi. Va shunga qaramay, uning chiqishi mening ekranimga aylanmoqda. Buning sababi, buyruq-p mushuklari mening $ PATH ni qanday qilib tortib olganligimdan qat'iy nazar haqiqiydir.

2
qo'shib qo'ydi
@eadmaster - bu qonuniy tashvish. Ammo, man buyrug'i ga qarasangiz, mantiqiy asosda da standart yordam dasturlarini topish maqsadini keltiradi har doim sizni hech bo'lmaganda qilishni istaysizmi: buyruq -p getconf PATH .
qo'shib qo'ydi muallif Bill Comer, manba
Bitta muammo faqat standart kommunallarni topish uchun kafolatlangan, shuning uchun u ba'zi hollarda ishlamaydi. Buni faqat POSIX standart funktsiyalari yordamida juda ixcham yechim deb biling. Uni boshqalardan ustun qo'yaman. (Men keyingi tahrirlarda sintaksisini o'zgartira olmaymiz deb umid qilaman);
qo'shib qo'ydi muallif Reshma, manba

type va qaysi yordam berishi kerakligini bilaman. Misol uchun:

$ type -a sudo
sudo is aliased to `/usr/bin/sudo'
sudo is /home/terdon/scripts/sudo
sudo is /usr/bin/sudo

Yuqoridagi misolda 3 mumkin sudo s, birinchisi taxallus va ikkitasi $ PATH . Siz faqat kerakli narsani bajarish uchun uni tahlil qilishingiz mumkin. Agar siz turi o'rnatilgan bo'lmagan qobiqni ishlatayotgan bo'lsangiz, , bilan bir xil ishni qila olasiz (garchi boshqa nomlarni aniqlamasa ham, muammo bo'lmasligi kerak , qaysidir darajada shell skriptlari bilan).

$ which -a sudo
/home/terdon/scripts/sudo
/usr/bin/sudo

Buni yodda tutingki, maqsadingiz mavjud skript nomiga asoslangan cheksiz pastadirni chetlab o'tish bo'lsa, quyidagilarni qilishingiz mumkin:

#!/usr/bin/env bash

## Get the name of the matching command from your
## $PATH, excluding the script itself ($0).
com=$(type -a $(basename $0) | grep -v $0 | head -n 1 | awk '{print $NF'})
## Run the command on the arguments passed
$com "[email protected]"

@Edimaster sharhlarda ko'rsatganidek, -a barcha tizimlarda mavjud bo'lmasligi uchun POSIX tomonidan aniqlanmagan. Keyinchalik, ko'chma yondashuv sizning $ PATH katalogingiz orqali qidirishdir:

#!/usr/bin/env bash

## Get the name of the matching command from your
## $PATH, excluding the script itself ($0).
com=$(find $(printf "%s" "$PATH" | sed 's/:/ /g') -name $(basename $0) |
      grep -v $0 | head -n 1)
## Run the command on the arguments passed
$com "[email protected]"
1
qo'shib qo'ydi
Afsuski, $ PATH uchun har qanday ishonchsizlik, har doim ham find ga qarash kerak. Biroq, har qanday holatda, $ PATH uchun har qanday ishonchsizlik asossiz va uni o'rnatgan administrator nima ish qilayotganini bilishi yoki yetarlicha bilib olishi kerak va biz hamma narsani to'xtatishimiz kerak ularning istaklarini chetga surishga harakat qilmoqda ...
qo'shib qo'ydi muallif Bill Comer, manba
@delmaster shunga o'xshab ko'rinadi, rahmat. Bunday holda, topish ni ishlatishingiz mumkin. Yangilangan javobni ko'ring.
qo'shib qo'ydi muallif Jamal, manba
PATH o'zgaruvchisini o'zgarmagan holda tark etish fikriga qaramasdan, "a" -ni tanlash standart emas .
qo'shib qo'ydi muallif Reshma, manba

Agar $ HOME/bin yo'lingiz $ PATH ichida bo'lmasa, uni tekshirib ko'rishingiz mumkin

if [ ! -a $(command -v $(basename $0)) ]; then
        YOUR SCRIPT
else
   echo "$(basename $0 already exists in $PATH"
fi
1
qo'shib qo'ydi
Fikr qoldiring = yomon xatti-harakatlar! Javobim bilan nima yomon?
qo'shib qo'ydi muallif mike, manba

O'zgartirilgan PATH buyrug'ini qidiring:

PATH=$(awk -F: 'sub(FS "'$HOME/bin'","")' <<<"$PATH") which sudo

Misol uchun:

$ which sudo
/usr/local/bin/sudo
$ PATH=$(awk -F: 'sub(FS "/usr/local/bin","")' <<<"$PATH") which sudo
/usr/bin/sudo
0
qo'shib qo'ydi
@eadmaster Siz foydalanayotgan tirnoqlarga e'tibor bering. Quyidagi kabi foydalaning: PATH = $ (awk -F: 'sub (FS' '$ (dirname $ 0)) "...
qo'shib qo'ydi muallif muru, manba
bu ishlamayapti: PATH = $ (awk -F: 'sub (FS "$ (dirname $ 0)", "") <<< "$ PATH") qaysi $ (basename $ 0)
qo'shib qo'ydi muallif Reshma, manba

Men juda ishonchli ko'rinadigan bu muqobilni topdim.

EXEPATHSLIST="/usr/bin /usr/sbin /bin /sbin /opt/$1/bin /usr/games /usr/local/bin /usr/local/games /system/bin /system/xbin"
for exepath in $EXEPATHSLIST
do
    if [ -x  $exepath/$1 ]; then
        $exepath/"[email protected]"
        exit $?
    fi
done

# alternative using command
command -p "[email protected]"
_ES=$? ; [ $_ES -ne 127 ] && exit $_ES

# more alternative search methods here
# ...

# else command not found
exit 127
0
qo'shib qo'ydi