Uzyskanie katalogu źródłowego skryptu Bash od wewnątrz

Jak uzyskać ścieżkę katalogu, w którym znajduje się skrypt Bash, wewnątrz tego skryptu?

Na przykład, powiedzmy, że chcę użyć skryptu Bash jako Launchera dla innej aplikacji. Chcę zmienić katalog roboczy na ten, w którym znajduje się skrypt Bash, aby móc operować na plikach w tym katalogu, w następujący sposób:

$ ./application
 4059
Author: Jiaaro, 2008-09-13

30 answers

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

Jest przydatnym jednowierszowcem, który da ci pełną nazwę katalogu skryptu bez względu na to, skąd jest wywoływany.

Będzie działać tak długo, jak ostatni składnik ścieżki użytej do znalezienia skryptu nie jest dowiązaniem symbolicznym (linki do katalogów są w porządku). Jeśli chcesz również rozwiązać jakiekolwiek linki do samego skryptu, potrzebujesz rozwiązania wielowierszowego:

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 && 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 && pwd )"

Ten ostatni będzie działał z dowolną kombinacją aliasów, source, bash -c, dowiązania symboliczne itp.

Uwaga: Jeśli cd do innego katalogu przed uruchomieniem tego fragmentu wynik może być niepoprawny! Uważaj też na $CDPATH gotchas .

Aby zrozumieć, jak to działa, spróbuj użyć tej bardziej wyrazistej formy:

#!/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" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
  echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"

I wydrukuje coś w stylu:

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'
 5400
Author: Dave Dopson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-14 04:57:44

Użycie dirname "$0":

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

Samo użycie pwd nie zadziała, jeśli nie uruchomisz skryptu z katalogu, w którym się znajduje.

[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
 686
Author: matt b,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-29 22:51:06

Polecenie dirname jest najbardziej podstawowe, po prostu parsuje ścieżkę do nazwy pliku poza zmienną $0 (Nazwa skryptu):

dirname "$0"

Ale, jak zauważyłmatt b , zwracana ścieżka różni się w zależności od sposobu wywoływania skryptu. pwd nie wykonuje tego zadania, ponieważ mówi Ci tylko, co jest bieżącym katalogiem, a nie w jakim katalogu znajduje się skrypt. Dodatkowo, jeśli zostanie wykonane dowiązanie symboliczne do skryptu, otrzymasz (prawdopodobnie względną) ścieżkę do miejsca, w którym link rezyduje, a nie rzeczywisty skrypt.

Niektórzy inni wspominali o komendzie readlink , ale w najprostszym przypadku możesz użyć:

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

Readlink rozwiąże ścieżkę skryptu do ścieżki bezwzględnej z katalogu głównego systemu plików. Tak więc wszystkie ścieżki zawierające pojedyncze lub podwójne kropki, tyldy i / lub dowiązania symboliczne zostaną rozwiązane na pełną ścieżkę.

Oto skrypt demonstrujący każdy z nich, 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))"

Uruchamianie tego skryptu w moim katalogu domowym, użycie ścieżki względnej:

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

Ponownie, ale używając pełnej ścieżki do skryptu:

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

Teraz zmiana katalogów:

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

I na koniec używając dowiązania symbolicznego do wykonania skryptu:

>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh 
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat
 382
Author: phatblat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-04 16:33:10
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

Działa dla wszystkich wersji, w tym

  • gdy wywołane przez multple depth soft link,
  • gdy plik to
  • gdy skrypt wywołany komendą" source " aka . (dot) operator.
  • gdy ARG $0 jest modyfikowany z wywołującego.
  • "./script"
  • "/full/path/to/script"
  • "/some/path/../../another/path/script"
  • "./some/folder/script"

Alternatywnie, jeśli skrypt bash jest relatywnym dowiązaniem symbolicznym, chcesz podążać za nim i zwracać pełna ścieżka skryptu linked-to:

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 jest podany w pełnej ścieżce, bez względu na to, jak jest nazywany.
Po prostu upewnij się, że zlokalizujesz to na początku skryptu.

Ten komentarz i Kod Copyleft, Licencja do wyboru na GPL2. 0 lub nowsza lub CC-SA 3.0 (creativecommons Share Alike) lub nowsza. (c) 2008. Wszelkie prawa zastrzeżone. Brak jakiejkolwiek gwarancji. Byłeś warned.
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463dd2bbaa02906d0d6656

 168
Author: user25866,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 11:21:43

Krótka odpowiedź:

`dirname $0`

Lub ( najlepiej):

$(dirname "$0")
 94
Author: Fabien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-19 06:59:25

Możesz użyć $BASH_SOURCE

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

Zauważ, że musisz użyć #!/ bin / bash i nie #!/ bin / sh od rozszerzenia bash

 91
Author: Mr Shark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-17 10:12:50

To powinno wystarczyć:

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

Działa z dowiązaniami symbolicznymi i spacjami w path. Zobacz strony podręcznika dla dirnamei readlink.

Edit:

Z komentarza wynika, że nie działa z Mac OS. Nie mam pojęcia dlaczego. Jakieś sugestie?

 58
Author: Simon Rigét,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-29 22:04:57

pwd może być użyty do znalezienia bieżącego katalogu roboczego i dirname do znalezienia katalogu określonego pliku (Komenda, która została uruchomiona, to $0, więc {[5] } powinna dać ci katalog bieżącego skryptu).

Jednakże dirname podaje dokładnie katalogową część nazwy pliku, która najprawdopodobniej będzie zależna od bieżącego katalogu roboczego. Jeśli twój skrypt z jakiegoś powodu musi zmienić katalog, to wyjście z dirname staje się bez znaczenia.

Proponuję:

#!/bin/bash

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

echo "Directory is $directory"

W ten sposób otrzymujesz katalog bezwzględny, a nie względny.

Ponieważ skrypt będzie uruchamiany w osobnej instancji bash, nie ma potrzeby przywracania katalogu roboczego po jego zakończeniu, ale jeśli z jakiegoś powodu chcesz zmienić skrypt z powrotem, możesz łatwo przypisać wartość pwd do zmiennej przed zmianą katalogu, do wykorzystania w przyszłości.

Chociaż tylko

cd `dirname $0`

Rozwiązuje specyficzne scenariusz w pytaniu, uważam, że absolutna ścieżka do bardziej użytecznych ogólnie.

 51
Author: SpoonMeiser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-01 15:23:56

Nie wydaje mi się, żeby to było takie proste jak inni. pwd nie działa, ponieważ bieżący katalog nie musi być katalogiem ze skryptem. $0 też nie zawsze ma informacje. Rozważ następujące trzy sposoby wywołania skryptu.

./script

/usr/bin/script

script

Na pierwszy i trzeci sposób $0 nie ma pełnej informacji o ścieżce. W drugim i trzecim pwd nie działają. Jedynym sposobem, aby uzyskać dir w trzeci sposób byłoby uruchomić przez ścieżkę i znaleźć plik z poprawnym mecz. Zasadniczo kod musiałby powtórzyć to, co robi SYSTEM OPERACYJNY.

Jednym ze sposobów zrobienia tego, o co prosisz, byłoby po prostu zakodowanie danych w katalogu / usr/share i odniesienie do nich za pomocą pełnej ścieżki. Dane i tak nie powinny być w katalogu / usr / bin, więc prawdopodobnie jest to rzecz do zrobienia.

 32
Author: 2 revs, 2 users 83%Jim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-02 14:56:57
SCRIPT_DIR=$( cd ${0%/*} && pwd -P )
 31
Author: P M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-30 11:28:27

To Pobiera bieżący katalog roboczy na Mac OS X 10.6.6:

DIR=$(cd "$(dirname "$0")"; pwd)
 24
Author: Pubguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-03 13:29:20

Jest to specyficzne dla Linuksa, ale przydałoby się:

SELF=$(readlink /proc/$$/fd/255)
 24
Author: Steve Baker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-22 00:07:53
$(dirname "$(readlink -f "$BASH_SOURCE")")
 24
Author: test11,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-13 04:36:30

Oto jednoelement zgodny z POSIX:

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

# test
echo $SCRIPT_PATH
 20
Author: lamawithonel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-15 07:28:08

Próbowałem każdego z nich i żaden z nich nie zadziałał. Jeden był bardzo blisko, ale miał mały błąd, który złamał go źle; zapomnieli zawinąć ścieżkę w cudzysłów.

Również wiele osób zakłada, że uruchamiasz skrypt z powłoki, więc zapomnij, gdy otworzysz nowy skrypt, domyślnie jest to twój dom.

Wypróbuj ten katalog dla rozmiaru:

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

To robi to dobrze, niezależnie od tego, jak lub gdzie go prowadzisz.

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

Aby było to naprawdę przydatne oto jak zmienić katalog uruchomionego skryptu:

cd "`dirname "$0"`"

Hope that helps

 16
Author: 4 revsMike Bethany,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-06 02:04:03

Użyłbym czegoś takiego:

# 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
 15
Author: Nicolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-21 03:57:55

Mała zmiana rozwiązania e-satis i 3bcdnlklvc04a wskazały w ich odpowiedź

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

To powinno działać we wszystkich przypadkach, które wymienili.

EDIT: zapobiec popd po nieudanym pushd, dzięki konsolebox

 14
Author: Fuwjax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:38

Oto prosty, poprawny sposób:

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

Wyjaśnienie:

  • ${BASH_SOURCE[0]} - Pełna ścieżka do skryptu. Wartość ta będzie poprawna nawet wtedy, gdy skrypt jest pozyskiwany, np. source <(echo 'echo $0') wyświetla bash , podczas gdy zastąpienie go ${BASH_SOURCE[0]} wyświetli pełną ścieżkę skryptu. (Oczywiście, zakłada to, że jesteś OK biorąc zależność od Bash.)

  • readlink -f - rekurencyjnie rozwiązuje wszelkie dowiązania symboliczne w podanej ścieżce. To jest Rozszerzenie GNU i nie jest dostępne na (np.) systemach BSD. Jeśli używasz Maca, możesz użyć Homebrew do zainstalowania GNU coreutils i zastąpić to greadlink -f.

  • I oczywiście dirname pobiera Katalog nadrzędny ścieżki.

 14
Author: James Ko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-20 07:53:23
#!/bin/sh
PRG="$0"

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

scriptdir=`dirname "$PRG"`
 12
Author: Monkeyboy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-13 01:28:47

$_ Warto wspomnieć jako alternatywę dla $0. Jeśli uruchamiasz skrypt z Basha, zaakceptowaną odpowiedź można skrócić do:

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

Zauważ, że to musi być pierwsza instrukcja w Twoim skrypcie.

 11
Author: hurrymaplelad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-16 19:05:51

Porównałem wiele udzielonych odpowiedzi i wymyśliłem kilka bardziej kompaktowych rozwiązań. Te zdają się obsługiwać wszystkie przypadki crazy edge, które wynikają z Twojej ulubionej kombinacji: {]}

  • ścieżki bezwzględne lub ścieżki względne
  • miękkie linki do plików i katalogów
  • Inwokacja jako script, bash script, bash -c script, source script, lub . script
  • spacje, tabulatory, nowe linie, unicode, itp. w katalogach i / lub nazwach plików
  • nazwy plików zaczynające się myślnikiem

Jeśli uruchamiasz z Linuksa, wydaje się, że użycie uchwytu proc jest najlepszym rozwiązaniem do zlokalizowania w pełni rozwiązanego źródła aktualnie uruchomionego skryptu (w sesji interaktywnej link wskazuje na odpowiednie /dev/pts/X):

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

Ma to trochę brzydoty, ale poprawka jest zwarta i łatwa do zrozumienia. Nie używamy tylko Bash prymitywów, ale nie przeszkadza mi to, ponieważ readlink znacznie upraszcza to zadanie. echo X dodaje X na końcu łańcucha zmiennej aby wszystkie końcowe spacje w nazwie pliku nie zostały zjedzone, a podstawienie parametru ${VAR%X} na końcu linii usunie X. Ponieważ readlink dodaje własną nową linię (która normalnie zostałaby zjedzona podczas zastępowania poleceń, gdyby nie nasza poprzednia sztuczka), musimy się tego pozbyć. Najłatwiej jest to osiągnąć za pomocą schematu cytowania $'', który pozwala nam używać sekwencji specjalnych, takich jak \n do reprezentowania nowych linii (w ten sposób można również łatwo utworzyć złośliwie nazwane katalogi i pliki).

Powyższe powinno zaspokoić Twoje potrzeby związane z lokalizacją aktualnie uruchomionego skryptu pod Linuksem, ale jeśli nie masz do dyspozycji proc systemu plików, lub jeśli próbujesz zlokalizować w pełni rozwiązaną ścieżkę jakiegoś innego pliku, być może poniższy kod okaże się pomocny. To tylko niewielka modyfikacja z powyższej jedynki. Jeśli bawisz się dziwnymi nazwami katalogów / plików, sprawdzanie wyjścia zarówno ls, jak i readlink jest informacyjne, ponieważ ls wyświetli "uproszczone" ścieżki, zastępując {[21] } dla rzeczy takich jak nowe linie.

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"
 10
Author: billyjmc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-25 19:14:09

Dla Systemów posiadających GNU coreutils readlink (np. linux):

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

Nie ma potrzeby używania BASH_SOURCE, gdy $0 zawiera nazwę pliku skryptu.

 10
Author: user1338062,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-13 04:34:37

Spróbuj użyć:

real=$(realpath $(dirname $0))
 8
Author: eeerahul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-06 11:20:08

Więc... Chyba mam ten. Spóźnienie na imprezę, ale myślę, że niektórzy docenią to, że tu są, że natkną się na ten wątek. Komentarze powinny wyjaśniać.

#!/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
Author: Geoff Nixon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-21 17:47:37

Hmm, jeśli w ścieżce basename & dirname po prostu nie będą go wycinać a chodzenie ścieżką jest trudne (co jeśli rodzic nie wyeksportował ścieżki!). Powłoka musi jednak mieć otwarty uchwyt do swojego skryptu, a w bash the handle is # 255.

SELF=`readlink /proc/$$/fd/255`
Mi pasuje.
 7
Author: Joshua,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-27 20:17:03

Wypróbuj następujące rozwiązanie kompatybilne krzyżowo:

CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"

Jako realpath lub readlink polecenia nie zawsze są dostępne (w zależności od systemu operacyjnego) i ${BASH_SOURCE[0]} jest dostępna tylko w powłoce bash.

Alternatywnie możesz wypróbować następującą funkcję w bash:

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

Ta funkcja przyjmuje 1 argument. Jeśli argument ma już ścieżkę bezwzględną, wypisuje ją taką, jaką jest, w przeciwnym razie wypisuje zmienną $PWD + argument nazwy pliku (bez ./ prefiks).

Powiązane:

 7
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-24 02:23:02

To działa w bash-3.2:

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

Oto przykład jego użycia:

Powiedzmy, że masz~/bin katalog, który znajduje się w twoim$PATH . W tym katalogu znajduje się skrypt a. It source S script ~ / bin / lib / B . Wiesz, gdzie dołączony skrypt jest względem oryginalnego (podkatalog lib ), ale nie gdzie jest względem bieżącego katalogu użytkownika.

Jest to rozwiązane przez następujące (wewnątrz A):

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

Nie ma znaczenia, gdzie jest użytkownik i jak wywołuje skrypt, to zawsze będzie działać.

 6
Author: Matt Tardiff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 06:44:30

To jedyny sposób, w jaki znalazłem wiarygodną informację:

SCRIPT_DIR=$(dirname $(cd "$(dirname "$BASH_SOURCE")"; pwd))
 6
Author: BillTorpey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-13 12:54:18

Żaden z nich nie działał dla skryptu bash uruchomionego przez Findera w OS X - skończyło się na użyciu:

SCRIPT_LOC="`ps -p $$ | sed /PID/d | sed s:.*/Network/:/Network/: |
sed s:.*/Volumes/:/Volumes/:`"
Nie jest ładna, ale daje radę.
 5
Author: tigfox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-14 17:23:28

Moim zdaniem najlepszym rozwiązaniem kompaktowym byłoby:

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

Nie można polegać na niczym innym niż Bash. Zastosowanie dirname, readlink i basename ostatecznie doprowadzi do problemów ze zgodnością, więc najlepiej ich unikać, jeśli w ogóle jest to możliwe.

 5
Author: AsymLabs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-08 14:24:13