ස්ක්‍රිප්ට් එකෙන්ම බාෂ් ස්ක්‍රිප්ටයක ප්‍රභව නාමාවලිය ලබා ගන්නේ කෙසේද


4957

එම ස්ක්‍රිප්ට් එක තුළ , බාෂ් ස්ක්‍රිප්ටයක් පිහිටා ඇති නාමාවලියෙහි මාවත ලබා ගන්නේ කෙසේද ?

වෙනත් යෙදුමක් සඳහා දියත් කිරීමක් ලෙස Bash ස්ක්‍රිප්ට් භාවිතා කිරීමට මට අවශ්‍යය. වැඩකරන නාමාවලිය Bash ස්ක්‍රිප්ට් පිහිටා ඇති ස්ථානයට වෙනස් කිරීමට මට අවශ්‍යය, එබැවින් මට එම නාමාවලියෙහි ඇති ගොනු මත ක්‍රියා කළ හැකිය.

$ ./application

69
නාමාවලි නාමයේ අවසානයේ නව රේඛා තිබේ නම් වර්තමාන විසඳුම් කිසිවක් ක්‍රියාත්මක නොවේ - විධාන ආදේශනය මඟින් ඒවා ඉවත් කරනු ලැබේ. මේ සඳහා වැඩ කිරීම සඳහා ඔබට විධාන ආදේශනය තුළ නව රේඛාවක් නොවන අක්ෂරයක් එකතු කළ හැකිය - DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd && echo x)"- සහ විධාන ආදේශනයකින් තොරව එය ඉවත් කරන්න - DIR="${DIR%x}".
l0b0

80
pm jpmc26 ඉතා පොදු අවස්ථා දෙකක් තිබේ: අනතුරු සහ කඩාකප්පල් කිරීම. යමෙකු, කොහේ හරි, යම් දෙයක් කළ පමණින්, පිටපතක් අනපේක්ෂිත ආකාරයකින් අසමත් නොවිය යුතුය mkdir $'\n'.
l0b0

24
ඒ ආකාරයෙන් තම පද්ධතිය කඩාකප්පල් කිරීමට මිනිසුන්ට ඉඩ දෙන ඕනෑම අයෙක් එවැනි ගැටළු හඳුනා ගැනීම සඳහා එය අතහැර දැමිය යුතු නැත ... එවැනි වැරැද්දක් කිරීමට හැකියාව ඇති පුද්ගලයින් බඳවා ගැනීම අඩුය. අවුරුදු 25 ක් තුළ මම කිසි විටෙකත් මෙවැනි දෙයක් කොතැනකවත් දැක නැත .... මේ නිසා අපට පර්ල් වැනි දේවල් සහ අපිරිසිදු පරීක්ෂාව වැනි පුරුදු තිබේ (එසේ පැවසීම නිසා මට ගිනි තැබෙනු ඇත :)
osirisgothra

3
Protection l0b0 ඔබට එකම ආරක්ෂාවක් අවශ්‍ය dirnameබවත්, නාමාවලිය -(උදා --help) සමඟ ආරම්භ කළ හැකි බවත් සලකන්න . DIR=$(reldir=$(dirname -- "$0"; echo x); reldir=${reldir%?x}; cd -- "$reldir" && pwd && echo x); DIR=${DIR%?x}. සමහර විට මෙය අධික ලෙස මරා දැමිය හැකිද?
ලකුණු_අන්ඩර්

56
මෙම විෂය පිළිබඳ මෙම Bash නිති අසන ප්‍රශ්න කියවීමට මම තරයේ යෝජනා කරමි .
Rany Albeg Wein

Answers:


6577
#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

ස්ක්‍රිප්ට් එක කොතැනින් කැඳවනු ලැබුවද එහි සම්පූර්ණ නාමාවලි නාමය ලබා දෙන ප්‍රයෝජනවත් එක්-ලයිනර් වේ.

ස්ක්‍රිප්ට් එක සෙවීම සඳහා භාවිතා කරන මාර්ගයේ අවසාන අංගය සමමුහුර්තයක් නොවන තාක් කල් එය ක්‍රියා කරනු ඇත (නාමාවලි සම්බන්ධතා හරි). ස්ක්‍රිප්ටයට ඇති ඕනෑම සම්බන්ධතාවයක් නිරාකරණය කිරීමට ඔබට අවශ්‍ය නම්, ඔබට බහු රේඛා විසඳුමක් අවශ්‍ය වේ:

#!/bin/bash

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"

මෙම අන්තිම එක යොමුවීම්, ඕනෑම සංකලනයක් සමග වැඩ කරන source, bash -c, symlinks, ආදිය

පරෙස්සම් වන්න: cdමෙම ස්නිපටය ධාවනය කිරීමට පෙර ඔබ වෙනත් නාමාවලියකට ගියහොත් , ප්‍රති result ලය වැරදියි!

එසේම, $CDPATHගොචාස් ගැන විමසිල්ලෙන් සිටින්න , සහ ප්‍රතිදානය stderr වෙත හරවා යැවීමට පරිශීලකයා දක්ෂ ලෙස සීඩී ඉක්මවා ඇත්නම් ( update_terminal_cwd >&2මැක් වෙත ඇමතීම වැනි ගැලවීමේ අනුපිළිවෙලද ඇතුළුව ). >/dev/null 2>&1ඔබගේ cdවිධානය අවසානයේ එකතු කිරීමෙන් හැකියාවන් දෙකම බලා ගනී.

එය ක්‍රියා කරන ආකාරය තේරුම් ගැනීමට, මෙම වඩාත් වාචික ස්වරූපය ක්‍රියාත්මක කිරීමට උත්සාහ කරන්න:

#!/bin/bash

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  TARGET="$(readlink "$SOURCE")"
  if [[ $TARGET == /* ]]; then
    echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
    SOURCE="$TARGET"
  else
    DIR="$( dirname "$SOURCE" )"
    echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
    SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
  fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
if [ "$DIR" != "$RDIR" ]; then
  echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"

එය මෙවැනි දෙයක් මුද්‍රණය කරයි:

SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'

27
ඔබ සමඟ වැඩ කරන විසඳුමක් ලබාදීම සඳහා user25866 මගින් පිළිතුර සමඟ මෙම ප්රවේශය ගැටෙයි හැකි source <script>හා bash <script>: DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)".
ඩෑන් මෝල්ඩින්

21
සමහර විට cdSTDOUT වෙත යමක් මුද්‍රණය කරයි! උදා: ඔබට $CDPATHතිබේ නම් .. මෙම නඩුව ආවරණය කිරීම සඳහා, භාවිතා කරන්නDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"
user716468

182
මෙම පිළිගත් පිළිතුර අවුලක් නැත, එය සිම්ලින්ක් සමඟ ක්‍රියා නොකරන අතර ඕනෑවට වඩා සංකීර්ණ වේ. dirname $(readlink -f $0)නිවැරදි විධානයයි. ටෙස්ට් කේස් එකක් සඳහා gist.github.com/tvlooy/cbfbdb111a4ebad8b93e බලන්න
tvlooy

167
vtvlooy IMO ඔබේ පිළිතුර හරියටම හරි නැත, මන්දයත් මාර්ගයේ ඉඩක් ඇති විට එය අසමත් වේ. නව රේඛා චරිතයකට වෙනස්ව, මෙය සිදුවිය නොහැක්කකි. dirname "$(readlink -f "$0")"සංකීර්ණත්වය එකතු නොකරන අතර අවම කරදර සඳහා සාධාරණ මිනුම වඩා ශක්තිමත් වේ.
ඒඩ්‍රියන් ගුන්ටර්

11
commenttvlooy ඔබේ අදහස macOS (හෝ බොහෝ විට BSD) නොගැලපෙන අතර පිළිගත් පිළිතුර වේ. readlink -f $0ලබා දෙයි readlink: illegal option -- f.
ඇලෙක්සැන්ඩර් ලුන්බර්ග්

876

භාවිතා කරන්න dirname "$0":

#!/bin/bash
echo "The script you are running has basename `basename "$0"`, dirname `dirname "$0"`"
echo "The present working directory is `pwd`"

pwdඔබ එහි ඇති නාමාවලියෙන් ස්ක්‍රිප්ට් ධාවනය නොකරන්නේ නම් තනිවම භාවිතා කිරීම ක්‍රියා නොකරනු ඇත.

[matt@server1 ~]$ pwd
/home/matt
[matt@server1 ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[matt@server1 ~]$ cd /tmp
[matt@server1 tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp

25
බෑෂ් වලින් ඔබ්බට ගෙන යා හැකි නම්, $ 0 සෑම විටම ප්‍රමාණවත් නොවනු ඇත. මෙම විධානය මාර්ගයෙහි හමු වූවා නම් මෙම කාර්යය කිරීමට ඔබට "-p $ 0" ටයිප් කරන්න.
ඩැරන්

10
Ar ඩැරන්: ඔබට භාවිතා කළ හැක්කේ type -pස්ක්‍රිප්ට් ක්‍රියාත්මක කළ හැකි නම් පමණි . ස්ක්‍රිප්ට් භාවිතයෙන් ක්‍රියාවට නංවන්නේ නම් සහ සියුම් සිදුරක් විවෘත කළ bash test2.shහැකි අතර වෙනත් නමක් වෙනත් තැනක ක්‍රියාත්මක කළ හැකිය.
ඩී. ෂව්ලි

90
Ar ඩැරන්: නමුත් ප්‍රශ්නය ටැග් කර ඇති නිසා bashසහ හැෂ්-බැන්ග් රේඛාවේ පැහැදිලිව සඳහන් කර ඇති /bin/bashහෙයින්, මම කියන්නේ බැෂිස්වාදය මත යැපීම තරමක් ආරක්ෂිත බවයි.
ජෝකිම් සෝවර්

34
+1, නමුත් භාවිතා කිරීමේ ගැටළුව dirname $0වන්නේ නාමාවලිය වත්මන් නාමාවලිය නම්, ඔබට ලැබෙනු .ඇත. ඔබ ස්ක්‍රිප්ටයේ නාමාවලි වෙනස් කිරීමට සහ ඔබ ලබාගත් මාර්ගය dirname $0නිරපේක්ෂ ලෙස භාවිතා කිරීමට බලාපොරොත්තු නොවන්නේ නම් එය හොඳයි . නිරපේක්ෂ මාර්ගය ලබා ගැනීමට: pushd `dirname $0` > /dev/null, SCRIPTPATH=`pwd`, popd > /dev/null: pastie.org/1489386 (නමුත්, නියත වශයෙන්ම ඒ මාවතේ පුළුල් කිරීමට වඩා හොඳ විදිහක් නැහැ?)
TJ Crowder

9
JTJ Crowder dirname $0ඔබ එය විචල්‍යයකට පවරා පසුව එය වැනි පිටපතක් දියත් කිරීමට භාවිතා කරන්නේ නම් එය ගැටළුවක් බව මට විශ්වාස නැත $dir/script.sh; 90% ක්ම මේ ආකාරයේ දේ සඳහා භාවිතා කිරීමේ අවස්ථාව මෙය යැයි මම සිතමි. ./script.shහොඳින් වැඩ කරයි.
matt b

516

මෙම dirnameවිධානය හුදෙක් කපා ගොනු නාමය සඳහා වන මාර්ගය දක්වා මාණකරනය ක්රියාත්මක, වඩාත් මූලික වේ $0(තිර රචනය නම) විචල්ය:

dirname "$0"

නමුත්, මැට් බී පෙන්වා දුන් පරිදි, පිටපත හැඳින්වෙන ආකාරය අනුව ආපසු යන මාර්ගය වෙනස් වේ. pwdකාර්යය නොකරන්නේ එය ඔබට පවසන්නේ වර්තමාන නාමාවලිය යනු කුමක්ද යන්න මිස ස්ක්‍රිප්ට් එක පිහිටා ඇති ඩිරෙක්ටරිය නොවේ. මීට අමතරව, ස්ක්‍රිප්ට් එකකට සංකේතාත්මක සම්බන්ධතාවයක් ක්‍රියාත්මක කරන්නේ නම්, ඔබට (බොහෝ විට සාපේක්ෂ) මාර්ගයක් ලැබෙනු ඇත. සබැඳිය වාසය කරන තැන මිස සත්‍ය පිටපත නොවේ.

තවත් සමහරු readlinkවිධානය සඳහන් කර ඇත , නමුත් එහි සරලම අවස්ථාවේදී ඔබට භාවිතා කළ හැකිය:

dirname "$(readlink -f "$0")"

readlinkගොනු පද්ධතියේ මුල සිට ස්ක්‍රිප්ට් මාර්ගය නිරපේක්ෂ මාර්ගයකට විසඳනු ඇත. එබැවින්, තනි හෝ ද්විත්ව තිත්, ටයිල්ඩ් සහ / හෝ සංකේතාත්මක සම්බන්ධතා අඩංගු ඕනෑම මාර්ගයක් සම්පූර්ණ මාර්ගයකට විසඳනු ඇත.

මෙහි, මෙම එක් එක් පෙන්නුම් තිර රචනය තියෙන්නේ whatdir.sh:

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename $0`"
echo "dirname: `dirname $0`"
echo "dirname/readlink: $(dirname $(readlink -f $0))"

සාපේක්ෂ මාර්ගයක් භාවිතා කරමින් මෙම පිටපත මගේ නිවසේ ධාවනය කිරීම:

>>>$ ./whatdir.sh 
pwd: /Users/phatblat
$0: ./whatdir.sh
basename: whatdir.sh
dirname: .
dirname/readlink: /Users/phatblat

නැවතත්, නමුත් පිටපතට සම්පූර්ණ මාර්ගය භාවිතා කිරීම:

>>>$ /Users/phatblat/whatdir.sh 
pwd: /Users/phatblat
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

දැන් නාමාවලි වෙනස් කිරීම:

>>>$ cd /tmp
>>>$ ~/whatdir.sh 
pwd: /tmp
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

පිටපත ක්‍රියාත්මක කිරීම සඳහා සංකේතාත්මක සබැඳියක් භාවිතා කිරීම:

>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh 
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat

13
readlinkපෙරනිමි ස්ථාපනය කිරීමේදී කිසියම් වේදිකාවක නොතිබෙනු ඇත. ඔබට හැකි නම් එය භාවිතා කිරීමෙන් වැළකී සිටීමට උත්සාහ කරන්න
TL

43
හිස් export SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
අවකාශයේ

13
OSX යොස්මයිට් 10.10.1 -fහි විකල්පයක් ලෙස හඳුනාගෙන නොමැත readlink. stat -fඒ වෙනුවට භාවිතා කිරීම කාර්යය කරයි. ස්තූතියි
cucu8

11
ඕඑස්එක්ස් හි, greadlinkමූලික වශයෙන් readlinkඅප සැවොම දන්නා දෙයකි . වේදිකාවේ ස්වාධීන අනුවාදය මෙන්න:dir=`greadlink -f ${BASH_SOURCE[0]} || readlink -f ${BASH_SOURCE[0]}`
රොබට්

6
හොඳ ඇමතුමක්, රොබට්. FYI, greadlinkbrew install coreutils
හෝම්බ rew

184
pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}"
if ([ -h "${SCRIPT_PATH}" ]); then
  while([ -h "${SCRIPT_PATH}" ]); do cd `dirname "$SCRIPT_PATH"`; 
  SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

ඇතුළුව සියලුම අනුවාද සඳහා ක්‍රියා කරයි

  • බහු ගැඹුරේ මෘදු සම්බන්ධකයක් හරහා කැඳවූ විට,
  • ගොනුව එය ගොනු කරන විට
  • ස්ක්‍රිප්ට් විධානය මඟින් කැඳවූ විට " source" aka .(dot) ක්‍රියාකරු.
  • $0ඇමතුම්කරුගෙන් ආර්ග් වෙනස් කළ විට .
  • "./script"
  • "/full/path/to/script"
  • "/some/path/../../another/path/script"
  • "./some/folder/script"

විකල්පයක් ලෙස, බැෂ් ස්ක්‍රිප්ට් එක සාපේක්ෂ සිම්ලින්ක් නම් ඔබට එය අනුගමනය කිරීමට අවශ්‍ය වන අතර සම්බන්ධිත ස්ක්‍රිප්ටයේ සම්පූර්ණ මාර්ගය නැවත ලබා දිය යුතුය:

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
if ([ -h "${SCRIPT_PATH}" ]) then
  while([ -h "${SCRIPT_PATH}" ]) do cd `dirname "$SCRIPT_PATH"`; SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

SCRIPT_PATHඑය කෙසේ හැඳින්වුවද සම්පූර්ණ මාර්ගයෙන් ලබා දී ඇත.
ස්ක්‍රිප්ට් එක ආරම්භයේදීම ඔබ මෙය සොයා ගැනීමට වග බලා ගන්න.

මෙම විවරණය සහ කේතය කොපිලෙෆ්ට්, GPL2.0 හෝ ඊට පසු තෝරා ගත හැකි බලපත්‍රය හෝ CC-SA 3.0 (CreativeCommons Share Alike) හෝ ඊට පසුව. (ඇ) 2008. සියලුම හිමිකම් ඇවිරිණි. කිසිදු ආකාරයක වගකීමක් නොමැත. ඔබට අනතුරු අඟවා ඇත.
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463d662


4
හොඳයි! SCRIPT_PATH = විසින් "pushd [...] popd / dev / null" වෙනුවට කෙටි කළ හැකිය readlink -f $(dirname "${VIRTUAL_ENV}");
ඊ-තෘප්තිමත්

5
Pushd භාවිතා කරනවා වෙනුවට ...; $ (cd dirname "${SCRIPT_PATH}"&& pwd) භාවිතා කිරීම වඩා හොඳ නොවේද? කෙසේ වෙතත් විශිෂ්ට පිටපතක්!
ඕවන්ස්

6
ස්ක්‍රිප්ටයක් cdඑහි වත්මන් ඩිරෙක්ටරියෙන් පිටතට යාම cdපසුකාලීනව නැවත ලබා ගැනීමේ බලාපොරොත්තුවෙන් භයානක ය : ඩිරෙක්ටරිය නැවත ආයාචනා කරන විට පවතින ඩිරෙක්ටරියට නැවත වෙනස් කිරීමට ස්ක්‍රිප්ටයට අවසර නොතිබිය හැකිය. (Pushd / popd සඳහාද එසේමය)
ඒඩ්‍රියන් ප්‍රොන්ක්

7
readlink -fGNU විශේෂිත වේ. BSD readlinkට එම විකල්පය නොමැත.
කරා බ්‍රයිට්වෙල්

3
සියලුම අනවශ්‍ය උපසිරැසි සමඟ ඇත්තේ කුමක්ද? ([ ... ])වඩා කාර්යක්ෂමතාව අඩු වන අතර [ ... ], එම කාර්ය සාධනය වෙනුවෙන් මෙහි දී ලබා දෙන හුදකලාවෙහි කිසිදු වාසියක් නොමැත.
චාල්ස් ඩෆි

110

කෙටි පිළිතුර:

`dirname $0`

හෝ ( වඩාත් සුදුසු ):

$(dirname "$0")

17
ඔබ ස්ක්‍රිප්ට් එක ප්‍රභව කළහොත් එය ක්‍රියා නොකරනු ඇත. "source my / script.sh"
අරුන්ප්‍රසාද් රාජ්කුමාර්

මම මගේ බාෂ් ස්ක්‍රිප්ට් වල නිතරම මෙය භාවිතා කරන්නේ දේවල් ස්වයංක්‍රීය කරන අතර බොහෝ විට එකම ස්ක්‍රිප්ට වෙනත් ස්ක්‍රිප්ට් ඉල්ලීමයි. මම sourceමේවා කිසි විටෙකත් භාවිතා නොකරන cd $(dirname $0)අතර මතක තබා ගැනීම පහසුය.
kqw

16
idvidstige: ${BASH_SOURCE[0]}වෙනුවට ක්‍රියා $0කරනු ඇතsource my/script.sh
තිමෝති ජෝන්ස්

Im තිමෝති ජෝන්ස්, බාෂ් හැර වෙනත් ෂෙල් එකකින් ලබා ගන්නේ නම් එය 100% ක්ම අසමත් වේ. ${BASH_SOURCE[0]}කිසිසේත් සතුටුදායක නොවේ. ${BASH_SOURCE:-0}වඩා හොඳයි.
Mathieu CAROFF

106

ඔබට භාවිතා කළ හැකිය $BASH_SOURCE:

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

ඔබ භාවිතා කළ යුතු බව සලකන්න, එය Bash දිගුවක් බැවින් #!/bin/bashනොවේ #!/bin/sh.


14
මම එසේ කරන විට ./foo/scriptඑසේ $(dirname $BASH_SOURCE)වේ ./foo.
තුරු

1
IllTill, මේ අවස්ථාවේ දී අපට ./foo/script හි realpathසම්පූර්ණ මාර්ගය ලබා ගැනීමට විධානය භාවිතා කළ හැකිය . එබැවින් dirname $(realpath ./foo/script) තිර රචනයේ මාවත ලබා දෙනු ඇත.
purushothaman poovai

73

මෙය කළ යුත්තේ:

DIR="$(dirname "$(readlink -f "$0")")"

මෙය සිම්ලින්ක් සහ මාර්ගයේ අවකාශයන් සමඟ ක්‍රියා කරයි.

dirnameසහ සඳහා man පිටු බලන්න readlink.

අදහස් දැක්වීමේ මාර්ගයෙන් එය මැක් ඕඑස් සමඟ වැඩ නොකරන බව පෙනේ. ඒ ඇයිදැයි මට අදහසක් නැත. යෝජනා තිබේද?


6
ඔබේ විසඳුම සමඟ, සම්පූර්ණ ඩිරෙක්ටරි මාර්ගය වෙනුවට ./script.shසංදර්ශන වැනි ස්ක්‍රිප්ට් .භාවිතා කිරීම
un නෝ නෙග්‍රියෝ සිකා

5
මැකෝස් හි කියවීම් සබැඳිය සඳහා -f විකල්පයක් නොමැත. statඒ වෙනුවට භාවිතා කරන්න . නමුත් තවමත්, එය පෙන්නුම් .කරන්නේ ඔබ 'මේ' ඩිර් හි සිටිනවාද යන්නයි.
ඩෙනිස් ද මෙනේස්

2
ඔබ හෝම්බ rew coreutilsවෙතින් ස්ථාපනය කර MacOS greadlinkහි -fවිකල්පය ලබා ගැනීමට භාවිතා කළ යුත්තේ එය ආවරණ යටතේ * BSD වන අතර ලිනක්ස් නොවේ.
dragon788

ඔබ දකුණු පස වටා ද්විත්ව උපුටා දැක්වීම් එකතු කළ යුතුය:DIR="$(dirname "$(readlink -f "$0")")"
hagello

60

pwdවත්මන් වැඩ කරන නාමාවලිය dirnameසොයා ගැනීමට සහ විශේෂිත ගොනුවක නාමාවලිය සොයා ගැනීමට භාවිතා කළ හැකිය (ක්‍රියාත්මක වූ විධානය $0, එසේ නම්, dirname $0ඔබට වර්තමාන ස්ක්‍රිප්ටයේ නාමාවලිය ලබා දිය යුතුය).

කෙසේ වෙතත්, dirnameගොනු නාමයේ නාමාවලි කොටස හරියටම ලබා දෙයි, එය වර්තමාන වැඩ කරන නාමාවලියට සාපේක්ෂව වැඩි නොවේ. කිසියම් හේතුවක් නිසා ඔබේ ස්ක්‍රිප්ටයට ඩිරෙක්ටරිය වෙනස් කිරීමට අවශ්‍ය නම්, එවිට ලැබෙන ප්‍රතිදානය dirnameඅර්ථ විරහිත වේ.

මම පහත සඳහන් දේ යෝජනා කරමි:

#!/bin/bash

reldir=`dirname $0`
cd $reldir
directory=`pwd`

echo "Directory is $directory"

මේ ආකාරයෙන්, ඔබට නිරපේක්ෂ, පසුව සාපේක්ෂ නාමාවලියක් ලැබේ.

ස්ක්‍රිප්ට් එක වෙනමම බාෂ් උදාහරණයකින් ක්‍රියාත්මක වන බැවින්, පසුව වැඩ කරන ඩිරෙක්ටරිය යථා තත්වයට පත් කිරීමේ අවශ්‍යතාවයක් නොමැත, නමුත් යම් හේතුවක් නිසා ඔබේ ස්ක්‍රිප්ට් එක නැවත වෙනස් කිරීමට අවශ්‍ය නම්, ඔබට pwdපෙර විචල්‍යයක වටිනාකම පහසුවෙන් ලබා දිය හැකිය. අනාගත භාවිතය සඳහා නාමාවලිය වෙනස් කරන්න.

සාධාරණ වුවත්

cd `dirname $0`

ප්‍රශ්නයේ නිශ්චිත තත්වය විසඳයි, සාමාන්‍යයෙන් වඩාත් ප්‍රයෝජනවත් වීමට නිරපේක්ෂ මාවතක් ඇති බව මට පෙනේ.


9
ඔබට මේ සියල්ල එක පේළියකින් කළ හැකිය: DIRECTORY = $ (cd dirname $0&& pwd)
dogbane

ස්ක්‍රිප්ට් වෙනත් ස්ක්‍රිප්ටයක් ප්‍රභව කළහොත් මෙය ක්‍රියා නොකරනු ඇති අතර ඔබට එහි නම දැන ගැනීමට අවශ්‍ය වේ.
ප්‍රතිස්ථාපනය කරන්න

52

පිළිගත් පිළිතුරේ එක් ලයිනර් එකක් පිටපත් කිරීම සඳහා මෙම පිටුවට නැවත නැවතත් පැමිණීම මට මහන්සියි. එහි ඇති ගැටළුව නම් තේරුම් ගැනීම සහ මතක තබා ගැනීම පහසු නැත.

මතක තබා ගැනීමට පහසු පිටපතක් මෙන්න:

DIR="$(dirname "${BASH_SOURCE[0]}")"  # get the directory name
DIR="$(realpath "${DIR}")"    # resolve its full path if need be

2
නැතහොත්, වඩාත් DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
අපැහැදිලි

මෙය පිළිගත් පිළිතුර නොවන්නේ ඇයි? realpathලූපයක් සමඟ "අතින්" නිරාකරණය කිරීමෙන් යම් වෙනසක් readlinkතිබේද? readlinkමෑන් පිටුව පවා පවසයිNote realpath(1) is the preferred command to use for canonicalization functionality.
පරිශීලක 9123

1
මාර්ගය වන විට අප realpathකලින් අයදුම් කළ යුතු නොවේද dirname? ස්ක්‍රිප්ට් ගොනුව සිම්ලින්ක් එකක් නම් ... එය වැනි දෙයක් ලබා දෙනු DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"ඇත. ඇත්තටම සයිමන් යෝජනා කළ පිළිතුරට ඉතා ආසන්නයි.
පරිශීලක 9123

9 User9123 මම හිතන්නේ පිළිගැනීම සියලු ජනප්‍රිය ෂෙල් / ඩිස්ට්‍රෝ සමඟ අනුකූල වීමට උත්සාහ කරයි. ඊටත් වඩා, ඔබ කිරීමට උත්සාහ කරන දේ මත පදනම්ව, බොහෝ විට මිනිසුන්ට අවශ්‍ය වන්නේ සත්‍ය ප්‍රභවයේ නාමාවලිය වෙනුවට සිම්ලින්ක් පිහිටා ඇති නාමාවලිය ලබා ගැනීමට ය.
වැන්ග්

37

මම හිතන්නේ නැහැ මෙය අනෙක් අය විසින් සිදු කර ඇති තරම් පහසුයි කියා. pwdවත්මන් ඩිරෙක්ටරිය ස්ක්‍රිප්ට් සමඟ ඇති නාමාවලිය නොවන බැවින් ක්‍රියා නොකරයි. $0සෑම විටම තොරතුරු නොමැත. පිටපතක් කැඳවීමට පහත දැක්වෙන ක්‍රම තුන සලකා බලන්න:

./script

/usr/bin/script

script

පළමු හා තෙවන ආකාරවල $0සම්පූර්ණ මාර්ග තොරතුරු නොමැත. දෙවන හා තෙවන විට, pwdක්රියා නොකරයි. තෙවන ආකාරයෙන් නාමාවලිය ලබා ගත හැකි එකම ක්‍රමය වනුයේ මාර්ගය හරහා දිවීම සහ නිවැරදි ගැලපීම සමඟ ගොනුව සොයා ගැනීමයි. මූලික වශයෙන් කේතයට මෙහෙයුම් පද්ධතිය කරන දේ නැවත කිරීමට සිදුවේ.

ඔබ ඉල්ලන දේ කිරීමට එක් ක්‍රමයක් වනුයේ /usr/shareනාමාවලියෙහි ඇති දත්ත දෘඩ කේතනය කිරීම සහ එහි සම්පූර්ණ මාවතෙන් එය යොමු කිරීමයි. දත්ත ෂෝඩ් /usr/binකෙසේ වෙතත් ඩිරෙක්ටරියේ නොතිබිය යුතුය , එබැවින් මෙය කළ යුතු දෙයයි.


9
ඔබ ඔහුගේ අදහස සනාථ කිරීමට අදහස් කරන්නේ නම්, කේත උදාහරණයකින් එය ගබඩා කර ඇති තැනකට ස්ක්‍රිප්ටයකට පිවිසිය හැකි බව ඔප්පු කරන්න.
රිචඩ් ඩුවර්

34
SCRIPT_DIR=$( cd ${0%/*} && pwd -P )

මෙය තෝරාගත් පිළිතුරට වඩා කෙටි වේ. ඒ වගේම වැඩ කරන බව පෙනේ. මෙය ඡන්ද 1000 ක් ලැබීමට සුදුසු බැවින් මිනිසුන් එය නොසලකා හරිනු ඇත.
පැට්රික්

2
පෙර පිළිතුරු බොහොමයක් විස්තරාත්මකව පැහැදිලි කර ඇති පරිදි, පිටපත ආයාචනා කරන ආකාරය මත පදනම්ව නිවැරදි තොරතුරු ලබා ගැනීමට සහතික $0නොවේ pwd.
IMSoP

34
$(dirname "$(readlink -f "$BASH_SOURCE")")

මම කැමතියි, $BASH_SOURCEඊට වඩා $0, එය පා readers කයන්ට පවා මනා දැනුමක් නැති නිසා. $(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
blobmaster

32

මෙය මැක් ඕඑස් එක්ස් 10.6.6 හි වත්මන් වැඩ නාමාවලිය ලබා ගනී:

DIR=$(cd "$(dirname "$0")"; pwd)

27

මෙය ලිනක්ස් විශේෂිත නමුත් ඔබට මෙය භාවිතා කළ හැකිය:

SELF=$(readlink /proc/$$/fd/255)

1
එය ද විශේෂිත වේ, නමුත් සමහර විට බාෂ්ගේ හැසිරීම වෙනස් වී තිබේද? /proc/fd/$$/255tty වෙත යොමු වන බවක් පෙනේ, නාමාවලියකට නොවේ. උදාහරණයක් ලෙස, මගේ වර්තමාන පිවිසුම් කවචයේ, 0, 1, 2, සහ 255 යන ගොනු විස්තර සියල්ලම යොමු වේ /dev/pts/4. කෙසේ වෙතත්, bash අත්පොතේ fd 255 ගැන සඳහන් නොවේ, එබැවින් මෙම හැසිරීම මත රඳා සිටීම අ
කීත් තොම්සන්

2
අන්තර් ක්‍රියාකාරී කවචය! = ස්ක්‍රිප්ට්. කෙසේ වෙතත් realpath ${BASH_SOURCE[0]};යන්න හොඳම ක්‍රමය බව පෙනේ.
ස්ටීව් බේකර්

23

මෙන්න POSIX අනුකූල එක්-ලයිනර්:

SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"`

# test
echo $SCRIPT_PATH

4
පිටපතක් තනිවම ධාවනය කිරීමේදී හෝ සුඩෝ භාවිතා කිරීමෙන් මට මෙය සාර්ථක විය, නමුත් මූලාශ්‍රය ඇමතීමේදී නොවේ ./script.sh
මයිකල් ආර්

cdනව මාර්ග නාමය මුද්‍රණය කිරීම සඳහා වින්‍යාස කර ඇති විට එය අසාර්ථක වේ.
ආරොන් ඩිගුල්ලා

18

මම මේ සියල්ල අත්හදා බැලුවෙමි. එකක් ඉතා සමීප නමුත් ඉතා කුඩා දෝෂයක් ඇති අතර එය දරුණු ලෙස බිඳ දැමීය. උද්ධෘත ලකුණු වලින් මාර්ගය ඔතා ගැනීමට ඔවුන්ට අමතක විය.

බොහෝ අය උපකල්පනය කරන්නේ ඔබ පිටපත ෂෙල් එකකින් ධාවනය කරන බවයි, එබැවින් ඔබ නව ස්ක්‍රිප්ට් එකක් විවෘත කළ විට එය ඔබේ නිවසට පෙරනිමිය.

ප්‍රමාණය සඳහා මෙම නාමාවලිය උත්සාහ කරන්න:

/var/No one/Thought/About Spaces Being/In a Directory/Name/And Here's your file.text

ඔබ එය ක්‍රියාත්මක කරන්නේ කෙසේද හෝ කොතැනද යන්න නොසලකා මෙය නිවැරදිව ලබා ගනී:

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename "$0"`"
echo "dirname: `dirname "$0"`"

එබැවින් එය සැබවින්ම ප්‍රයෝජනවත් කිරීම සඳහා මෙහි ධාවනය වන ස්ක්‍රිප්ටයේ නාමාවලියට වෙනස් වන්නේ කෙසේද:

cd "`dirname "$0"`"

4
ස්ක්‍රිප්ට් වෙනත් ස්ක්‍රිප්ට් එකකින් ලබා ගන්නේ නම් එය ක්‍රියා නොකරයි.
ප්‍රතිස්ථාපනය කරන්න

Direct 0 හි අවසාන කොටස වෙනත් නාමාවලියක ( ln -s ../bin64/foo /usr/bin/foo) ඇතුළත් කිරීමකට යොමු කරන සංකේතාත්මක සබැඳියක් නම් මෙය ක්‍රියා නොකරයි .
hagello

17

මෙන්න සරල, නිවැරදි ක්‍රමය:

actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")

පැහැදිලි කිරීම:

  • ${BASH_SOURCE[0]}- පිටපතට සම්පූර්ණ මාර්ගය. මෙම වටිනාකම එහි තිර රචනය උදා: මූලාශ්ර කොට ඇත විට පවා, නිවැරදි වනු ඇත source <(echo 'echo $0')පිටපත් bash ඒ වෙනුවට අතර, ${BASH_SOURCE[0]}තිර පිටපත් සම්පූර්ණ මාර්ගය මුද්රණය කරනු ඇත. (ඇත්ත වශයෙන්ම, මෙය උපකල්පනය කරන්නේ ඔබ බාෂ් මත යැපීමක් කර ඇති බවයි.)

  • readlink -f- නිශ්චිත මාර්ගයේ ඇති ඕනෑම සිම්ලින්ක් පුනරාවර්තනය කරයි. මෙය GNU දිගුවක් වන අතර (උදාහරණයක් ලෙස) BSD පද්ධති වල නොමැත. ඔබ මැක් ධාවනය කරමින් සිටින්නේ නම්, ඔබ GNU ස්ථාපනය කිරීමට බරපැනක් භාවිතා කළ හැකි coreutilsහා සමග මෙම පක්ෂය විස්ථාපනය greadlink -f.

  • ඇත්ත වශයෙන්ම මාර්ගයේ dirnameමව් නාමාවලිය ලැබේ.


1
greadlink -fඅවාසනාවකට sourceමැක් හි පිටපත ඇතුළත් කළ විට effectively
ලදායී

17

මෙය කිරීමට කෙටිම හා අලංකාරම ක්‍රමය නම්:

#!/bin/bash
DIRECTORY=$(cd `dirname $0` && pwd)
echo $DIRECTORY

මෙය සියලු වේදිකාවල වැඩ කරන අතර සුපිරි පිරිසිදුයි.

වැඩි විස්තර " එම බාෂ් ස්ක්‍රිප්ට් එක තිබෙන්නේ කුමන නාමාවලියෙන්ද? "


විශිෂ්ට පිරිසිදු විසඳුමක්, නමුත් ගොනුව සමමුහුර්ත කර ඇත්නම් මෙය ක්‍රියා නොකරනු ඇත.
රූටර්

16

මම මේ වගේ දෙයක් පාවිච්චි කරනවා:

# retrieve the full pathname of the called script
scriptPath=$(which $0)

# check whether the path is a link or not
if [ -L $scriptPath ]; then

    # it is a link then retrieve the target path and get the directory name
    sourceDir=$(dirname $(readlink -f $scriptPath))

else

    # otherwise just get the directory name of the script path
    sourceDir=$(dirname $scriptPath)

fi

සැබෑ එක මෙයයි! සරල ලෙසද ක්‍රියා shකරයි! සරල dirname "$0"පදනම් වූ විසඳුම් සමඟ ගැටළුව : ස්ක්‍රිප්ට් එකෙහි ඇති $PATHඅතර එය මාර්ගයකින් තොරව ආයාචනා කළහොත් ඒවා වැරදි ප්‍රති .ල ලබා දෙනු ඇත.
නොටින් ලැයිස්තුව

Not නොටින් ලැයිස්තුව එසේ නොවේ. එම කේත රචනය හට හරහා සොයා නම් PATH, $0නියත ගොනු අඩංගු වේ. A අඩංගු සාපේක්ෂ හෝ නිරපේක්ෂ ගොනු නාමයක් සමඟ ස්ක්‍රිප්ට් ආයාචනය කරන්නේ නම් /, $0එය අඩංගු වේ.
නීල් මේයූ

උපුටා ගත් පිටපතක් සඳහා ක්‍රියා නොකරනු ඇත.
අමිත් නායිදු

16

මෙය ඊ-සැට් විසඳුමට සුළු සංශෝධනයක් වන අතර 3bcdnlklvc04a ඔවුන්ගේ පිළිතුරෙන් පෙන්වා දී ඇත :

SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
    SCRIPT_DIR="$PWD"
    popd > /dev/null
}    

ඔවුන් ලැයිස්තුගත කර ඇති සියලුම අවස්ථා වලදී මෙය තවමත් ක්‍රියාත්මක විය යුතුය.

කොන්සොල්බොක්ස් වලට ස්තූතියි, popdඅසමත් වීමෙන් පසු මෙය වළක්වනු ඇත pushd.


මෙය සිම්ලින්ක් එකක නමට වඩා “සැබෑ” නාමය ලබා ගැනීමට පරිපූර්ණව ක්‍රියා කරයි. ඔබට ස්තුතියි!
ජේ ටේලර්

1
වඩා හොඳSCRIPT_DIR=''; pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && { SCRIPT_DIR=$PWD; popd > /dev/null; }
konsolebox

onkonsolebox, ඔබ ආරක්ෂා කිරීමට උත්සාහ කරන්නේ කුමක් ද? මම සාමාන්‍යයෙන් තාර්කික කොන්දේසි ඇතුළත් කිරීමේ රසිකයෙක්, නමුත් ඔබ තල්ලු කිරීමේදී දුටු විශේෂිත දෝෂය කුමක්ද? හිස් SCRIPT_DIR එකක් ආපසු ලබා දෙනවා වෙනුවට එය කෙලින්ම හැසිරවීමට ක්‍රමයක් සොයා ගැනීමට මම ගැලපේ.
ෆුජැක්ස්

U ෆුජැක්ස් අසමත් popdවූ අවස්ථාවන්හිදී (දුර්ලභ අවස්ථාවන්හිදී පවා) වළක්වා ගැනීම සඳහා ස්වාභාවික පුහුණුව pushd. හා නඩුවේ pushdඅසමත්, ඔබ අගය කළ යුතු හිතන්නේ SCRIPT_DIR? තාර්කික යැයි පෙනෙන දේ හෝ එක් පරිශීලකයෙකුට කැමති දේ අනුව ක්‍රියාව වෙනස් විය හැකි නමුත් නිසැකවම popdකිරීම වැරදිය.
konsolebox

එම සියලු pushd popdඅනතුරු වළක්වා ගත හැක්කේ ඒවා අතහැර දමා විධාන ආදේශනයක cd+ pwdකොටා තිබීමෙනි. SCRIPT_DIR=$(...)
අමිත් නායිදු

16

GNU coreutils සහිත පද්ධති සඳහා readlink(උදා: ලිනක්ස්):

$(readlink -f "$(dirname "$0")")

ස්ක්‍රිප්ට් ගොනු නාමය අඩංගු වන BASH_SOURCEවිට භාවිතා කිරීමට අවශ්‍ය නැත $0.


3
ස්ක්‍රිප්ට් එක උපුටා ගත්තේ නැත්නම්. හෝ 'ප්‍රභවය' නම් එය තවමත් එය ලබාගත් ඕනෑම පිටපතක් වනු ඇත, නැතහොත්, විධාන රේඛාවෙන් නම්, '-බෑෂ්' (ටීටී පිවිසුම) හෝ 'බාෂ්' ('බාෂ්-එල්' හරහා ආයාචනා කරනු ලැබේ) හෝ '/ බින් / bash '(අන්තර්ක්‍රියාකාරී නොවන පිවිසුම් කවචයක් ලෙස ආයාචනය කර ඇත)
osirisgothra

මම dirnameඇමතුම වටා දෙවන උපුටා දැක්වීම් යුගලයක් එක් කළෙමි . නාමාවලි මාර්ගයේ අවකාශයන් තිබේ නම් අවශ්‍ය වේ.
user1338062

14
#!/bin/sh
PRG="$0"

# need this for relative symlinks
while [ -h "$PRG" ] ; do
   PRG=`readlink "$PRG"`
done

scriptdir=`dirname "$PRG"`

මම එය විවිධ පද්ධති හරහා පරීක්ෂා කර නැත. නමුත් මෙම විසඳුම අවම වශයෙන් උබුන්ටු මත වහාම ක්‍රියාත්මක වන එකකි, මට!
නේටස් ඩ rew ව්

$0උපුටා ගත් පිටපතක් සඳහා ක්‍රියා නොකරනු ඇත
අමිත් නායිදු

13

$_විකල්පයක් ලෙස සඳහන් කිරීම වටී $0. ඔබ බාෂ් වෙතින් ස්ක්‍රිප්ට් එකක් ධාවනය කරන්නේ නම්, පිළිගත් පිළිතුර කෙටි කළ හැකිය:

DIR="$( dirname "$_" )"

මෙය ඔබගේ ස්ක්‍රිප්ටයේ පළමු ප්‍රකාශය විය යුතු බව සලකන්න.


4
ඔබ sourceහෝ .තිර රචනය නම් එය කැඩී යයි . එවැනි අවස්ථාවන්හිදී, $_ඔබ පෙර ධාවනය කළ අවසාන විධානයේ අවසාන පරාමිතිය අඩංගු වේ .. $BASH_SOURCEසෑම විටම ක්රියා කරයි.
clacke

11

මම ලබා දී ඇති පිළිතුරු බොහොමයක් සංසන්දනය කර ඇති අතර තවත් සංයුක්ත විසඳුම් කිහිපයක් ඉදිරිපත් කරමි. ඔබගේ ප්‍රියතම සංයෝජනයෙන් පැන නගින පිස්සු අද්දර සිද්ධීන් සියල්ලම මේවා හසුරුවන බව පෙනේ:

  • නිරපේක්ෂ මාර්ග හෝ සාපේක්ෂ මාර්ග
  • ගොනු සහ නාමාවලි මෘදු සබැඳි
  • පිහිට පැතීමක් ලෙස script, bash script, bash -c script, source script, හෝ. script
  • නාමාවලි සහ / හෝ ගොනු නාමයන්හි අවකාශ, ටැබ්, නව රේඛා, යුනිකෝඩ් යනාදිය
  • ලිපිගොනු යටි ඉරකින් ආරම්භ වේ

ඔබ ලිනක්ස් වෙතින් ධාවනය කරන්නේ නම් proc, දැනට ක්‍රියාත්මක වන ස්ක්‍රිප්ටයේ සම්පුර්ණයෙන්ම විසඳා ඇති ප්‍රභවය සොයා ගැනීමට හොඳම විසඳුම හසුරුව භාවිතා කරන බව පෙනේ (අන්තර්ක්‍රියාකාරී සැසියකදී, සබැඳිය අදාළ ඒවාට යොමු කරයි /dev/pts/X):

resolved="$(readlink /proc/$$/fd/255 && echo X)" && resolved="${resolved%$'\nX'}"

මෙය කුඩා අවලස්සන බවක් ඇත, නමුත් නිවැරදි කිරීම සංයුක්ත හා තේරුම් ගැනීමට පහසුය. අපි භාවිතා කරන්නේ ප්‍රාථමික ප්‍රාථමිකයන් පමණක් නොවේ, නමුත් readlinkකාර්යය සැලකිය යුතු ලෙස සරල කරන නිසා මම ඒ සමඟ හොඳින් සිටිමි . මෙම echo Xක එකතු Xගොනු නාමය ඕනෑම අගින් ඇද whitespace අනුභව එසේ නැත ලබා, සහ පරාමිතිය ආදේශන විචල්ය string අවසානය දක්වා ${VAR%X}රේඛාව අවසානයේ ඉවත් වී යයි X. readlinkඑයට ආවේණික වූ නව රේඛාවක් එක් කරන හෙයින් (සාමාන්‍යයෙන් අපගේ පෙර උපක්‍රම සඳහා නොවේ නම් විධාන ආදේශනයේදී එය අනුභව කරනු ඇත), අපද එයින් මිදිය යුතුය. $''උපුටා දැක්වීමේ යෝජනා ක්‍රමය භාවිතයෙන් මෙය වඩාත් පහසුවෙන් ඉටු කර ගත හැකි අතර , එමඟින් අපට ගැලවීමේ අනුක්‍රම භාවිතා කළ හැකිය\n නව රේඛා නිරූපණය කිරීම සඳහා (මෙය ඔබට පහසුවෙන් නම් කළ නාමාවලි සහ ලිපිගොනු සෑදිය හැකි ආකාරයයි).

ඉහත සඳහන් වන්නේ ලිනක්ස් හි දැනට ක්‍රියාත්මක ස්ක්‍රිප්ට් එක සොයා ගැනීම සඳහා වන ඔබේ අවශ්‍යතා සපුරාලිය යුතුය, නමුත් ඔබ සතුව procගොනු පද්ධතිය නොමැති නම් හෝ වෙනත් ගොනුවක සම්පුර්ණයෙන්ම විසඳන ලද මාර්ගය සොයා ගැනීමට ඔබ උත්සාහ කරන්නේ නම්, සමහර විට ඔබ පහත කේතය ප්‍රයෝජනවත් බව සොයා ගන්න. එය ඉහත එක් ලයිනර් වෙතින් සුළු වෙනස් කිරීමක් පමණි. ඔයා තමයි අමුතු බහලුම / ගොනු නාමය වටා ක්රීඩා නම්, දෙකම ප්රතිදානය පරීක්ෂා lsහා readlinkලෙස, තොරතුරු වේ lslocate විධානයෙන් ආදේශ, මාර්ගයන් "සරල" ?හිස් පේලි ගැන වගේ දේවල්.

absolute_path=$(readlink -e -- "${BASH_SOURCE[0]}" && echo x) && absolute_path=${absolute_path%?x}
dir=$(dirname -- "$absolute_path" && echo x) && dir=${dir%?x}
file=$(basename -- "$absolute_path" && echo x) && file=${file%?x}

ls -l -- "$dir/$file"
printf '$absolute_path: "%s"\n' "$absolute_path"

මට /dev/pts/30උබුන්ටු 14.10 ඩෙස්ක්ටොප් එකෙන් බැෂ් එක ලැබෙනවා .
ඩෑන් ඩස්කල්ස්කු

AnDanDascalescu එක් ලයිනර් භාවිතා කරනවාද? නැතිනම් පතුලේ ඇති සම්පූර්ණ කේත ස්නිපටයද? ඔබ එය කිසියම් ව්‍යාකූල මාර්ග නාමයක් පෝෂණය කළාද?
billyjmc

එක් රේඛාව ප්ලස් තවත් රේඛාව echo $resolved, මම එය ගැලවීම d, chmod +x d, ./d.
ඩෑන් ඩස්කල්ස්කු

ScanDanDascalescu ඔබේ ස්ක්‍රිප්ටයේ පළමු පේළිය විය යුතුයි#!/bin/bash
billyjmc

10

භාවිතා කිරීමට උත්සාහ කරන්න:

real=$(realpath $(dirname $0))

1
මට දැන ගැනීමට අවශ්‍ය වන්නේ, මේ ක්‍රමය හොඳ නොවන්නේ ඇයි? එය මට නරක හා නිවැරදි යැයි පෙනුනේ නැත. එය පහත් කොට සැලකීමට හේතුව කිසිවෙකුට පැහැදිලි කළ හැකිද?
ෂෝ යා

7
realpath යනු සම්මත උපයෝගීතාවයක් නොවේ.
ස්ටීව් බෙනට්

2
ලිනක්ස් හි, රියල්පාත් යනු සම්මත උපයෝගීතාවයකි (GNU coreutils පැකේජයේ කොටසක්), නමුත් එය බාෂ් බිල්ට් එකක් නොවේ (එනම්, බාෂ් විසින්ම සපයන ලද ශ්‍රිතයක්). ඔබ Linux ක්රියාත්මක කරන්නේ නම්, මෙම ක්රමය බොහෝ විට වැඩ කරන, මම ආදේශ කියලා නමුත් $0සඳහා ${BASH_SOURCE[0]}ඒ නිසා මෙම ක්රමය උත්සවයකට ද ඇතුලු ඕනෑම තැනක වැඩ කරන බව.
ඩග් රිචඩ්සන්

3
මෙම පිළිතුරේ මෙහෙයුම් අනුපිළිවෙල වැරදිය. ඔබ මුලින්ම සිම්ලින්ක් එක නිරාකරණය කළ යුතුය, පසුව කරන්න, dirnameමන්දයත් එහි අවසාන කොටස $0සිම්ලින්ක් මෙන් එකම ඩිරෙක්ටරියේ නොමැති ගොනුවකට යොමු කරන සිම්ලින්ක් එකක් විය හැකි බැවිනි. මෙම පිළිතුරේ විස්තර කර ඇති විසඳුම ලැබෙන්නේ එය ගබඩා කර ඇති සිම්ලින්ක් නාමාවලියෙහි දිශාවට මිස ඉලක්කයේ නාමාවලියට නොවේ. තවද, මෙම විසඳුම උපුටා දැක්වීම අස්ථානගත වී ඇත. මාර්ගයෙහි විශේෂ අක්ෂර අඩංගු නම් එය ක්‍රියා නොකරනු ඇත.
hagello

3
dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
කොස්ටියන්ටින් පොනෝමරෙන්කෝ

9

පහත දැක්වෙන හරස් අනුකූල විසඳුම උත්සාහ කරන්න:

CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"

(මෙහෙයුම් පද්ධතිය මත පදනම්ව) වැනි realpathහෝ readlinkලබා ගත නොහැකි විධානයන් ලෙස .

සටහන: Bash හි, ඒ ${BASH_SOURCE[0]}වෙනුවට භාවිතා කිරීම රෙකමදාරු කරනු ලැබේ $0, එසේ නොමැති නම් ගොනුව ( source/ .) ලබා ගැනීමේදී මාර්ගය කැඩී යා හැක .

විකල්පයක් ලෙස ඔබට පහත දැක්වෙන ශ්‍රිතය bash වලින් උත්සාහ කළ හැකිය:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

මෙම ශ්‍රිතය තර්ක 1 ක් ගනී. තර්කයට දැනටමත් නිරපේක්ෂ මාර්ගයක් තිබේ නම්, එය එලෙසම මුද්‍රණය කරන්න, එසේ නොමැතිනම් $PWDවිචල්ය + ගොනු නාම තර්කය මුද්‍රණය කරන්න ( ./උපසර්ගය නොමැතිව ).

ආශ්‍රිත:


කරුණාකර රියල්පාත් ශ්‍රිතය ගැන වැඩි විස්තර කරන්න.
ක්‍රිස්

1
H ක්‍රිස් realpathශ්‍රිතය තර්ක 1 ක් ගනී. තර්කයට දැනටමත් නිරපේක්ෂ මාර්ගයක් තිබේ නම්, එය එලෙසම මුද්‍රණය $PWDකරන්න , එසේ නොමැතිනම් + ගොනු නාමය මුද්‍රණය කරන්න ( ./උපසර්ගය නොමැතිව ).
kenorb

ස්ක්‍රිප්ට් එක සමමුහුර්ත කර ඇති විට ඔබේ හරස් අනුකූල විසඳුම ක්‍රියා නොකරයි.
ජකුබ් ජිරුට්කා

9

මම විශ්වාස කරනවා මට මේක ලැබුණා කියලා. මම සාදයට ප්‍රමාදයි, නමුත් මම හිතන්නේ සමහරු මෙම ත්‍රෙඩ් එක හමු වුවහොත් එය මෙහි සිටීම අගය කරනු ඇත. අදහස් පැහැදිලි කළ යුතුය:

#!/bin/sh # dash bash ksh # !zsh (issues). G. Nixon, 12/2013. Public domain.

## 'linkread' or 'fullpath' or (you choose) is a little tool to recursively
## dereference symbolic links (ala 'readlink') until the originating file
## is found. This is effectively the same function provided in stdlib.h as
## 'realpath' and on the command line in GNU 'readlink -f'.

## Neither of these tools, however, are particularly accessible on the many
## systems that do not have the GNU implementation of readlink, nor ship
## with a system compiler (not to mention the requisite knowledge of C).

## This script is written with portability and (to the extent possible, speed)
## in mind, hence the use of printf for echo and case statements where they
## can be substituded for test, though I've had to scale back a bit on that.

## It is (to the best of my knowledge) written in standard POSIX shell, and
## has been tested with bash-as-bin-sh, dash, and ksh93. zsh seems to have
## issues with it, though I'm not sure why; so probably best to avoid for now.

## Particularly useful (in fact, the reason I wrote this) is the fact that
## it can be used within a shell script to find the path of the script itself.
## (I am sure the shell knows this already; but most likely for the sake of
## security it is not made readily available. The implementation of "$0"
## specificies that the $0 must be the location of **last** symbolic link in
## a chain, or wherever it resides in the path.) This can be used for some
## ...interesting things, like self-duplicating and self-modifiying scripts.

## Currently supported are three errors: whether the file specified exists
## (ala ENOENT), whether its target exists/is accessible; and the special
## case of when a sybolic link references itself "foo -> foo": a common error
## for beginners, since 'ln' does not produce an error if the order of link
## and target are reversed on the command line. (See POSIX signal ELOOP.)

## It would probably be rather simple to write to use this as a basis for
## a pure shell implementation of the 'symlinks' util included with Linux.

## As an aside, the amount of code below **completely** belies the amount
## effort it took to get this right -- but I guess that's coding for you.

##===-------------------------------------------------------------------===##

for argv; do :; done # Last parameter on command line, for options parsing.

## Error messages. Use functions so that we can sub in when the error occurs.

recurses(){ printf "Self-referential:\n\t$argv ->\n\t$argv\n" ;}
dangling(){ printf "Broken symlink:\n\t$argv ->\n\t"$(readlink "$argv")"\n" ;}
errnoent(){ printf "No such file: "$@"\n" ;} # Borrow a horrible signal name.

# Probably best not to install as 'pathfull', if you can avoid it.

pathfull(){ cd "$(dirname "$@")"; link="$(readlink "$(basename "$@")")"

## 'test and 'ls' report different status for bad symlinks, so we use this.

 if [ ! -e "$@" ]; then if $(ls -d "$@" 2>/dev/null) 2>/dev/null;  then
    errnoent 1>&2; exit 1; elif [ ! -e "$@" -a "$link" = "$@" ];   then
    recurses 1>&2; exit 1; elif [ ! -e "$@" ] && [ ! -z "$link" ]; then
    dangling 1>&2; exit 1; fi
 fi

## Not a link, but there might be one in the path, so 'cd' and 'pwd'.

 if [ -z "$link" ]; then if [ "$(dirname "$@" | cut -c1)" = '/' ]; then
   printf "$@\n"; exit 0; else printf "$(pwd)/$(basename "$@")\n"; fi; exit 0
 fi

## Walk the symlinks back to the origin. Calls itself recursivly as needed.

 while [ "$link" ]; do
   cd "$(dirname "$link")"; newlink="$(readlink "$(basename "$link")")"
   case "$newlink" in
    "$link") dangling 1>&2 && exit 1                                       ;;
         '') printf "$(pwd)/$(basename "$link")\n"; exit 0                 ;;
          *) link="$newlink" && pathfull "$link"                           ;;
   esac
 done
 printf "$(pwd)/$(basename "$newlink")\n"
}

## Demo. Install somewhere deep in the filesystem, then symlink somewhere 
## else, symlink again (maybe with a different name) elsewhere, and link
## back into the directory you started in (or something.) The absolute path
## of the script will always be reported in the usage, along with "$0".

if [ -z "$argv" ]; then scriptname="$(pathfull "$0")"

# Yay ANSI l33t codes! Fancy.
 printf "\n\033[3mfrom/as: \033[4m$0\033[0m\n\n\033[1mUSAGE:\033[0m   "
 printf "\033[4m$scriptname\033[24m [ link | file | dir ]\n\n         "
 printf "Recursive readlink for the authoritative file, symlink after "
 printf "symlink.\n\n\n         \033[4m$scriptname\033[24m\n\n        "
 printf " From within an invocation of a script, locate the script's "
 printf "own file\n         (no matter where it has been linked or "
 printf "from where it is being called).\n\n"

else pathfull "$@"
fi

8

ස්ක්‍රිප්ට් තොරතුරු ලබා ගැනීමට මෙය කෙටි ක්‍රම වේ:

ෆෝල්ඩර සහ ගොනු:

    Script: "/tmp/src dir/test.sh"
    Calling folder: "/tmp/src dir/other"

මෙම විධානයන් භාවිතා කිරීම:

    echo Script-Dir : `dirname "$(realpath $0)"`
    echo Script-Dir : $( cd ${0%/*} && pwd -P )
    echo Script-Dir : $(dirname "$(readlink -f "$0")")
    echo
    echo Script-Name : `basename "$(realpath $0)"`
    echo Script-Name : `basename $0`
    echo
    echo Script-Dir-Relative : `dirname "$BASH_SOURCE"`
    echo Script-Dir-Relative : `dirname $0`
    echo
    echo Calling-Dir : `pwd`

මට මෙම ප්‍රතිදානය ලැබුණි:

     Script-Dir : /tmp/src dir
     Script-Dir : /tmp/src dir
     Script-Dir : /tmp/src dir

     Script-Name : test.sh
     Script-Name : test.sh

     Script-Dir-Relative : ..
     Script-Dir-Relative : ..

     Calling-Dir : /tmp/src dir/other

මෙයද බලන්න: https://pastebin.com/J8KjxrPF



සරල වැඩ සංස්කරණයක් සොයා ගැනීම දුෂ්කර බැවින් මගේ පිළිතුර හරි යැයි මම සිතමි. මෙහිදී ඔබට කැමති කේතය ගත හැකිය. උදා: cd + pwd, dirname + realpath හෝ dirname + readlink. සියලුම කොටස් මීට පෙර පවතින බව මට විශ්වාස නැත. බොහෝ පිළිතුරු සංකීර්ණ හා අධික ලෙස පටවා ඇත. මෙන්න ඔබට භාවිතා කිරීමට කැමති කේතය ඉවත් කළ හැකිය. අවම වශයෙන් කරුණාකර අනාගතයේදී මට අවශ්‍ය පරිදි එය ඉවත් නොකරන්න: D
User8461

8

මෙය bash-3.2 හි ක්‍රියාත්මක වේ:

path="$( dirname "$( which "$0" )" )"

ඔබ සතුව ~/binනාමාවලියක් තිබේ නම් $PATH, ඔබට Aමෙම නාමාවලිය තුළ ඇත. එය පිටපත ප්‍රභව කරයි ~/bin/lib/B. ඇතුළත් කළ ස්ක්‍රිප්ට් එක libඋප බහලුමේ මුල් පිටපතට සාපේක්ෂව කොතැනදැයි ඔබ දන්නවා , නමුත් එය පරිශීලකයාගේ වත්මන් නාමාවලියට සාපේක්ෂව කොතැනද යන්න නොවේ.

මෙය පහත (ඇතුළත A) මගින් විසඳනු ලැබේ :

source "$( dirname "$( which "$0" )" )/lib/B"

පරිශීලකයා සිටින්නේ කොතැනද යන්න හෝ ඔහු ස්ක්‍රිප්ට් අමතන්නේ කෙසේද යන්න ගැටළුවක් නොවේ, මෙය සැමවිටම ක්‍රියාත්මක වේ.


3
කාරණය whichඉතා විවාදාත්මක ය. type,, hashසහ වෙනත් බිල්ඩින්වරු එකම දේ බාෂ් වලදී වඩා හොඳින් කරති. whichඑය වඩා අතේ ගෙන යා හැකි ය, එය ඇත්ත වශයෙන්ම whichtcsh වැනි වෙනත් ෂෙල් වෙඩි වල භාවිතා නොවූවත්, එය බිල්ඩින් ලෙස ඇත.
මොනිකා නැවත

"සැමවිටම"? කොහෙත්ම නැහැ. whichබාහිර මෙවලමක් වීම, එය මව් කවචයට සමාන ලෙස ක්‍රියා කරන බව විශ්වාස කිරීමට ඔබට හේතුවක් නැත.
චාල්ස් ඩෆි

7

මගේ දැක්ම අනුව හොඳම සංයුක්ත විසඳුම වනුයේ:

"$( cd "$( echo "${BASH_SOURCE[0]%/*}" )"; pwd )"

බාෂ් හැර වෙනත් කිසිවක් කෙරෙහි විශ්වාසයක් නැත. භාවිතය dirname, readlinkසහ basenameඅවසානයේදී අනුකූලතා ගැටළු වලට තුඩු දෙනු ඇත, එබැවින් හැකි නම් ඒවා වළක්වා ගත හැකිය.


2
ඔබ බොහෝ විට ඒ සඳහා කප්පාදුවක් එකතු කළ යුතුය : "$( cd "$( echo "${BASH_SOURCE[0]%/*}/" )"; pwd )". ඔබ එසේ නොකළහොත් ඔබට මූල නාමාවලිය සමඟ ගැටලු ඇති වේ. එසේම ඔබට echo භාවිතා කිරීමට සිදුවන්නේ ඇයි?
konsolebox

dirnameහා basenamePOSIX, ඉතින් ඇයි වැලැක්විමට ඒවා භාවිතා සම්මත කරන්නේ? සබැඳි: dirname,basename
myrdd

අමතර ක්‍රියාදාමයන් දෙකක් වළක්වා ගැනීම සහ ෂෙල් බිල්ට් වලට ඇලී සිටීම ඊට එක් හේතුවක් විය හැකිය.
අමිත් නායිදු
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.