Skriptning mutlaq yo'lini olish uchun ko'chma usul bormi?

(Zsh) skriptining mutlaq yo'lini aniqlash uchun ko'chma usul nima?

Linuxda men shunga o'xshash narsani ishlataman

mypath=$(readlink -f $0)

... lekin bu portativ emas. (Masalan, darvin bo'yicha readlink -f bayrog'ini tanimaydi yoki hech qanday ekvivalenti yo'q.) (Buning uchun readlink shubhasiz, juda qorong'i ko'rinadigan hack.)

Portativ usul yana nima?

25
qo'shib qo'ydi muallif Stéphane Chazelas, manba

7 javoblar

zsh bilan faqat:

mypath=$0:A

realpath() va readlink() boshqa funktsiyalar uchun standart funktsiyalar (ikkinchisi tizim chaqiruvi), realpath va Readlink standart buyruq emas, ammo ba'zi bir tizimlar turli xil xatti-harakatlar va xususiyatlar bilan bir yoki ikkinchisiga yoki ikkalasiga ega.

Odatda, ko'chma uchun perl ga murojaat qilishingiz mumkin:

abs_path() {
  perl -MCwd -le '
    for (@ARGV) {
      if ($p = Cwd::abs_path $_) {
        print $p;
      } else {
        warn "abs_path: $_: $!\n";
        $ret = 1;
      }
    }
    exit $ret' "[email protected]"
}

GNU-ning real-path() (GNU readlink -e ) dan farqli ravishda readlink -f uning dirname qilgani qadar mavjud.

23
qo'shib qo'ydi
Eslatma: bu .zshrc uchun ishlamaydi: bu yozuv < buning o'rniga.
qo'shib qo'ydi muallif James Qualtrough, manba

Zsh da sizga quyidagilarni amalga oshirishingiz mumkin:

mypath=${0:a}

Yoki, skriptning joylashgan katalogini olish uchun:

mydir=${0:a:h}

Manba: zshexpn (1) man sahifa, TARIX kengaytirish, kichik bo'lim Modifikatorlar (yoki oddiygina info -f zsh -n Modifiers ).

20
qo'shib qo'ydi
GNU ning readlink -f ekvivalenti $ 0: A bo'lishi kerak.
qo'shib qo'ydi muallif Stéphane Chazelas, manba
Shirin! Men shunga o'xshash narsalarni qidiraman va izlayotgan zsh manpagesning barcha qismini o'qir edim, ammo "Tarixni kengaytirish" ga qarashim uchun hech qachon bunday bo'lmaydi.
qo'shib qo'ydi muallif Vucar Timnärakrul, manba

Men buni bir necha yillardan beri foydalandim:

# The absolute, canonical ( no ".." ) path to this script
canonical=$(cd -P -- "$(dirname -- "$0")" && printf '%s\n' "$(pwd -P)/$(basename -- "$0")")
11
qo'shib qo'ydi
GNU-ning readlink -f ga mos kelmasa, skript o'z-o'zidan belgilanadigan belgidir.
qo'shib qo'ydi muallif Stéphane Chazelas, manba
menga yoqdi! hozirgacha bu portativ. Solaris, OmniOS, Linux, Mac va Cygwin da Windows 2008-da ishlaydi.
qo'shib qo'ydi muallif Tim Kennedy, manba
zsh bilan Ubuntu 16.04 da, buni to'g'ridan-to'g'ri yoki pastki qismda (tavsiya etilganidek) mening uyimda (/home/ville ) amalga oshirsam, kodi>/home/ville/zsh kodini kiriting.
qo'shib qo'ydi muallif Jonas, manba

Ushbu sintaksis har qanday Bourne shell tarzi tarjimoniga ko'chirilishi kerak ( bash , ksh88 , ksh93 , zsh mksh , dash va busybox sh ):

mypath=$(exec 2>/dev/null;cd -- $(dirname "$0"); unset PWD; /usr/bin/pwd || /bin/pwd || pwd)
echo mypath=$mypath

This version adds compatibility to the legacy AT&T Bourne shell (non POSIX):

mypath=`dirname "$0"`
mypath=`exec 2>/dev/null;(cd -- "$mypath") && cd -- "$mypath"|| cd "$mypath"; unset PWD; /usr/bin/pwd || /bin/pwd || pwd`
echo mypath=$mypath
8
qo'shib qo'ydi
@Schily Men buni bilaman. Agar qobiq - ga ishonsa, eski buyruqqa qaytadi.
qo'shib qo'ydi muallif Eric Scrivner, manba
@moose Siz qanday operatsion tizimni ishlaysiz?
qo'shib qo'ydi muallif Eric Scrivner, manba
@mikeserv moose, zsh va dirname bilan bir muammo haqida sharh qoldirgan, lekin tezda uni izohlashni qoldiradigan passerby
qo'shib qo'ydi muallif Eric Scrivner, manba
@schily Siz yana bir oz batafsilroq gapira olasizmi? Mening skriptimni eski bourne qobig'i ostida sinab ko'rdingizmi va buni muvaffaqiyatsiz deb bilasizmi?
qo'shib qo'ydi muallif Eric Scrivner, manba
rahmat. Lekin, $ PWD ni ochib bo'lmadi, deb o'ylayman - siz uni faqat cd-P. kabi mutlaq oqimga o'rnatishingiz mumkin. Bourneshellda ishlaydiganiga shubhamiz bor, lekin bu siz uchun sinovdan o'tgan barcha ishlarda ishlashi kerak. baribir men uchun.
qo'shib qo'ydi muallif Bill Comer, manba
moose kim? nima?
qo'shib qo'ydi muallif Bill Comer, manba
OK, tomonga o'girildikten keyin buni ko'rib turibman. BTW: Bourne Shell plyonka-L/-P ni qo'llab-quvvatlamaydi, lekin 1989 yildan buyon har doim ssilkalar uchun tekshiradigan haqiqiy yo'l nomini qaytaradi.
qo'shib qo'ydi muallif schily, manba
Bourne Shell barcha keraksiz argumentlarni e'tiborsiz qoldiradi va chdir() ga birinchi dalilga (sizning namunangizda - ) ishlaydi. Agar siz tekshirib ko'rishni istasangiz, portativ Bourne Shellni sourceforge.net/projects/schilytools/files va original SVr4 funktsiyasi o'rnatilgan ikkilik osh ni tekshiring. Ikkilangan sh yoki bosh - yangi saqlangan variant.
qo'shib qo'ydi muallif schily, manba
Sizning Bourne Shell skriptingiz Bourne Shell bilan ishlamaydi, chunki Bourne Shell CD (1) uchun getopt() ni ishlatmaydi.
qo'shib qo'ydi muallif schily, manba

Siz haqiqatan ham mutlaq yo'lni, ya'ni ildiz katalogidan bir yo'lni nazarda tutgan deb hisoblasangiz:

case $0 in
  /*) mypath=$0;;
  *) mypath=$PWD/$0;;
esac

Bu, har qanday Bourne uslubidagi qobig'ida ishlaydi.

Agar siz barcha ramziy aloqalarni hal qilish yo'lini nazarda tutgan bo'lsangiz, bu boshqa masala. Linux-da ishlaydigan readlink -f , OS/X, AIX, HP/UX yoki Solaris-da emas, balki FreeBSD, NetBSD, OpenBSD va Cygwin-da ishlaydi. Agar sizda readlink bo'lsa, uni loopda qo'ng'iroq qilishingiz mumkin:

realpath() {
  [ -e "$1" ] || return
  case $1 in
    /*) :;;
    *) set "$PWD/$1";;
  esac
  while [ -L "$1" ]; do
    set "${1%/*}" "$(readlink "$1")"
    case $2 in
      /*) set "$2";;
      *) if [ -z "$1" ]; then set "/$2"; else set "$(cd "$1" && pwd -P)/$2"; fi;;
    esac
  done
  case $1 in
    */.|*/..) set "$(cd "$1" && pwd -P)";;
    */./*|*/../*) set "$(cd "${1%/*}" && pwd -P)/${1##*/}"
  esac
  realpath=$1
}

Agar readlink bo'lmasangiz, uni ls -n bilan taxmin qilishingiz mumkin, ammo bu faqat ls Fayl nomida chop etish mumkin bo'lgan belgilar.

poor_mans_readlink() {
  if [ -L "$1" ]; then
    set -- "$1" "$(LC_ALL=C command ls -n -- "$2"; echo z)"
    set -- "${2%??}"
    set -- "${2#*"$1 -> "}"
  fi
  printf '%s\n' "$1"
}

realpath funktsiyasi bu nomlarni katalog nomlari uchun ishlatmasa, u holda, bu kodni o'zgartirish uchun z aytmoqchi.)

4
qo'shib qo'ydi
Stefan Chazelas Touch Stefan; LC_ALL = Javob busybox ls StefanStane phane (agar u ism UTF-8da bo'lsa, latin1 sizga bitta ? kodini beradi). O'ylaymanki, bu eski savdo do'konlarda ham.
qo'shib qo'ydi muallif Valters Vingolds, manba
@ StéphaneChazelas Men bir nechta xatolikni aniqladim, ammo keng qamrovli tarzda tekshirilmadim. Ba'zi holatlarda (ayrim kataloglarda ijro etilish ruxsatnomalari etishmasligi tashqari), men hali ham bunday holatlarda hal qila olmasligini bilib qo'ying, men bu chekkaning ishi bilan shug'ullanmayman.
qo'shib qo'ydi muallif Valters Vingolds, manba
@Gilles - bu busybox nima? o'tishiga qarab busybox ls < kodi> 2011 yildan buyon kodni o'zgartirishga ega emas. busybox ls - 2013 yil - bu narsani qilmaydi. Bu biriga - 2012 yil - ishi . Ushbu nima uchun sababini tushuntirishi mumkin. busybox ni Unicode qo'llab-quvvatlashi bilan qurdingizmi - wchar-quvvatlashni kiritish uchunmi? mkinitcpio busybox to'plamidagi tuzish variantlarini tekshirish uchun uni boshqalarga berishni xohlashingiz mumkin.
qo'shib qo'ydi muallif Bill Comer, manba
Gilles - men bu javobni dastlab noto'g'ri deb o'ylayman - yoki uning hech bo'lmaganda bittasi. mangling fayl nomlari mantralaringizni ishonchli deb hisoblasa-da, albatta poor_mans_readlink juda yaxshi bajarilgan. Agar meni tahrir qilishning mehribonligini qilsangiz - har qanday tahrir qilish kerak - va keyin meni ping, men bu mening ovozimni qaytarish istayman.
qo'shib qo'ydi muallif Bill Comer, manba
Chiqish terminalga o'tmasa, bosmadan chiqarilmagan belgilarni manglayapti har qanday ls ilovasi haqida bilasizmi?
qo'shib qo'ydi muallif Stéphane Chazelas, manba

Joriy katalogda yoki sizning qobiq skriptini ishga tushirgan katalogda ruxsat berishni amalga oshirgan holda - kerakli katalogga mutlaq yo'l kerak bo'lsa, cd .

cd xususiyatlarining 10-bosqichi

Agar -P parametri amalda bo'lsa, pwd -P tomonidan chiqariladigan $ PWD kodi>. Joriy katalogni aniqlash uchun yangi papkada yoki katalogning istalgan ota-onasidan ruxsat etilmagan bo'lsa, $ PWD muhit o'zgaruvchining qiymati aniqlanmagan.

And pwd -P ustida

Standart chiqishga yozilgan yo'lning turi ramziy havola fayllariga murojaat qiladigan qismlarga ega emas. pwd yordam dasturining standart chiqishiga yozish uchun bir nechta usullar mavjud bo'lsa, bitta/slash belgisi bilan boshlanadigan va ikkita/slash belgisi bilan boshlangan bir yoki bir nechta varag'i bo'lsa, u yo'lning nomini yakka/slash belgisi.

Buning sababi cd -P joriy ish katalogini pwd -P -ga va cd - $ OLDPWD ni bosib chiqarishni talab qiladi:

mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -

OUTPUT

/home/mikeserv/test/ln

kuting ...

cd -P . ; cd . ; cd -

OUTPUT

/home/mikeserv/test/dir

Va cd - bilan bosib chiqarganimda, $ OLDPWD ni yozyapman. cd -P. $ PWD endi cd sozlamalari $ PWD >/ - shuning uchun boshqa o'zgaruvchilarga ehtiyojim yo'q. Va, aslida, . tagiga kerak bo'lmaslik kerak, lekin interfaol qobiqda $ PWD uchun $ HOME ga tiklashning aniq bir xatti-harakatlari mavjud cd noma'lum bo'lsa. Demak, bu nafaqat rivojlanish odatidir.

Buning uchun $ {0%/*} dagi yo'lda yuqoridagi narsani bajarish faqat $ 0 ning yo'lini tekshirish uchun etarli bo'lishi kerak, lekin $ 0 - bu o'z-o'zidan yumshoq aloqadir, afsuski, katalogni o'zgartira olmaysiz.

Mana, buni bajaradigan funksiya:

zpath() { cd -P . || return
    _out() { printf "%s$_zdlm\n" "$PWD/${1##*/}"; }
    _cd()  { cd -P "$1" ; } >/dev/null 2>&1
    while [ $# -gt 0 ] && _cd .
    do  if     _cd "$1" 
        then   _out
        elif ! [ -L "$1" ] && [ -e "$1" ] 
        then   _cd "${1%/*}"; _out "$1"
        elif   [ -L "$1" ]
        then   ( while set -- "${1%?/}"; _cd "${1%/*}"; [ -L "${1##*/}" ]
                 do    set " $1" "$(_cd -; ls -nd -- "$1"; echo /)"
                       set -- "${2#*"$1" -> }"
                 done; _out "$1" 
    );  else   ( PS4=ERR:\ NO_SUCH_PATH; set -x; : "$1" )
    fi; _cd -; shift; done
    unset -f _out _cd; unset -v _zdlm                                    
}

U hozirgi qobiqdagi kabi ko'p ishlarni bajarishga intiladi - biroq pastki chiziqlarni chaqirmasdan - xatoliklar va kataloglarga ishora qiladigan yumshoq yo'nalishlarga chaqirilganlar mavjud bo'lsa-da. Bu POSIX mos qobiq va POSIX mos keluvchi ls va toza _function() nom maydoniga bog'liq. Keyinchalik, u holda u holda mavjud bo'lgan qobiq funksiyalari unset ustiga yozishingiz mumkin. Umuman olganda, ushbu bog'liqliklar barcha Unix mashinasida ishonchli tarzda ta'minlanishi kerak.

Argumentlar bilan yoki mustaqil bo'lmagan holda chaqirgan birinchi narsa, $ PWD ning qanotiy qiymatiga qayta tiklanishi - u erda mavjud bo'lgan barcha bog'lanishlarni kerakli holatlarda hal qiladi. Argumentlarsiz chaqirilgan va bu haqda; lekin ular bilan chaqiriladi va u har bir yo'l uchun yo'lni aniqlaydi va kanonizlaydi, nima uchun stderr ga xat yoziladi.

Ko'pincha joriy qobiqda ishlayotganligi sababli u biron bir uzunlikdagi dalillar ro'yxatini tuzishi kerak. Bundan tashqari u $ _ zdlm o'zgarmaydiganini (u ham bo'lsa, unset s) ni qidiradi va C-eskirgan qiymatini darhol har birining har bir argumentini o'ng tomonda hamisha bitta \ n ewline xarakteriga ega bo'ladi.

Bu katalog katalogini o'zgartiradi, lekin uning qanot qiymatiga moslashdan tashqari, u $ PWD ga ta'sir qilmaydi, lekin $ OLDPWD hech qanday hisobga olinmaydi vaqt o'tishi bilan.

Har bir dalilni imkon qadar qisqa vaqt ichida tark etishga harakat qiladi. Avval cd kodini $ 1 ga yozib olishga harakat qiladi. Agar u stdout uchun argümanning kanonik yo'lini yozishga qodir bo'lsa. Agar u buni qila olmasa $ 1 mavjudligini tekshirmaydi va u yumshoq aloqa emas. Agar haqiqat bo'lsa, u chop etiladi.

Shunday qilib, agar $ 1 katalogga ishora qilmaydigan ramziy havola bo'lmasa, qobiqning manzilga murojaat qilish huquqiga ega bo'lgan har qanday fayl turi argumentini boshqaradi. Bunday holatda u while pastki qavat ichida ishlaydi.

U bog'ni o'qish uchun ls deb nomlanadi. Mavjud papkaning dastlabki qiymatiga o'zgartirilishi kerak, shuning uchun har qanday referent yo'llarini ishonchli boshqarishi va shuning uchun buyruq substitusionida funktsiya bajariladi:

cd -...ls...echo /

It strips from the left of ls's OUTPUT as little as it must to fully contain the link's name and the string ->. While I at first tried to avoid do this with shift and $IFS it turns out this is the most reliable method as near as I can figure. This is the same thing Gilles's poor_mans_readlink does - and it is well done.

ls dan qaytib kelgan fayl, albatta, yumshoq aloqa bo'lmaguncha, bu jarayonni aylanish jarayonida takrorlaydi. Shu nuqtada, cd bilan oldingi kabi, bu yo'lni yozadi.

Misoldan foydalanish:

zpath \
    /tmp/script \   #symlink to $HOME/test/dir/script.sh
    ln \            #symlink to ./dir/
    ln/nl \         #symlink to ../..
    /dev/fd/0 \     #currently a here-document like : dash <<\HD
    /dev/fd/1 \     #(zlink) | dash
    file \          #regular file                                             
    doesntexist \   #doesnt exist
    /dev/disk/by-path/pci-0000:00:16.2-usb-0:3:1.0-scsi-0:0:0:0 \
    /dev/./././././././null \
    . ..      

OUTPUT

/home/mikeserv/test/dir/script.sh
/home/mikeserv/test/dir/
/home/mikeserv/test/
/tmp/zshtpKRVx (deleted)
/proc/17420/fd/pipe:[1782312]
/home/mikeserv/test/file
ERR: NO_SUCH_PATH: doesntexist
/dev/sdd
/dev/null
/home/mikeserv/test/
/home/mikeserv/

Yoki ehtimol ...

ls
dir/  file  file?  folder/  [email protected]  [email protected]  script*  [email protected]  [email protected]

zdlm=\\0 zpath * | cat -A

OUTPUT

/home/mikeserv/test/dir/^@$               
/home/mikeserv/test/file^@$
/home/mikeserv/test/file$
^@$
/home/mikeserv/test/folder/^@$
/home/mikeserv/test/file$               #'link' -> 'file\n'
^@$
/home/mikeserv/test/dir/^@$             #'ln' -> './dir'
/home/mikeserv/test/script^@$
/home/mikeserv/test/dir/script.sh^@$    #'script3' -> './dir/script.sh'
/home/mikeserv/test/dir/script.sh^@$    #'script4' -> '/tmp/script' -> ...
1
qo'shib qo'ydi

Agar algoritmni qayta tiklashga to'sqinlik qiladigan bo'lsa, python vaqtida simpatik bir liner haqida nima deyish mumkin?

function readlink { python -c "import os.path; print os.path.realpath('$1')"; }

same as https://stackoverflow.com/a/7305217

0
qo'shib qo'ydi