Jak Mogę uzyskać katalog źródłowy skryptu Bash z samego skryptu?

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

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
 5264
Author: Peter Mortensen, 2008-09-12

30 answers

#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && 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:

#!/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 )"

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

Uwaga: Jeśli cd przed uruchomieniem tego fragmentu do innego katalogu, wynik może być nieprawidłowy!

Uważaj też na $CDPATH jeśli użytkownik ma nadpisaną płytę cd w celu przekierowania wyjścia na stderr (w tym sekwencje specjalne, takie jak wywołanieupdate_terminal_cwd >&2 na komputerze Mac), to wyświetlane są efekty uboczne. Dodanie >/dev/null 2>&1 na końcu polecenia cd zajmie się obiema możliwościami.

Aby zrozumieć, jak to działa, spróbuj uruchomić to bardziej zwięzłe forma:

#!/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'"

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'
 6969
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
2020-06-30 18:54:55

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
 956
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
2021-01-20 02:08:09

The dirname polecenie 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 wykonany link symboliczny do skryptu, otrzymasz (prawdopodobnie względny) ścieżka do miejsca, w którym znajduje się link, 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 tych, 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, za pomocą ścieżka względna:

>>>$ ./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
 545
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
2021-01-20 03:36:50
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

  • wywołane przez łącze miękkie o wielu głębokościach,
  • 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 względnym dowiązaniem symbolicznym, chcesz podążać za nim i zwracać pełną ścieżkę linked - to 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 jest podany w pełnej ścieżce, bez względu na to, jak jest nazywany.

Upewnij się, że zlokalizujesz to na początku skryptu.

 186
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
2021-01-20 02:27:25

Możesz użyć $BASH_SOURCE:

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

Zauważ, że musisz użyć #!/bin/bash, a nie #!/bin/sh, ponieważ jest to rozszerzenie Bash.

 113
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
2020-01-18 18:33:37

Krótka odpowiedź:

`dirname $0`

Lub ( najlepiej):

$(dirname "$0")
 111
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

To powinno wystarczyć:

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

Działa z dowiązaniami symbolicznymi i spacjami w path.

Zobacz strony podręcznika dla dirname i readlink.

Z komentarza wygląda na to, że nie działa z Mac OS. Nie mam pojęcia dlaczego. Jakieś sugestie?

 82
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
2020-03-19 20:15:18

Oto łatwy do zapamiętania skrypt:

DIR="$(dirname "${BASH_SOURCE[0]}")"  # Get the directory name
DIR="$(realpath "${DIR}")"    # Resolve its full path if need be
 78
Author: Thamme Gowda,
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
2021-01-20 04:54:23

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 skrypt z jakiegoś powodu musi zmienić katalog, to wyjście z dirname staje się bezsensowne.

I zasugeruj:

#!/bin/bash

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

echo "Directory is $directory"

W ten sposób otrzymujesz katalog absolutny, 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 konkretny scenariusz w pytaniu, I znajdź absolutną ścieżkę do bardziej użytecznych ogólnie.

 65
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
2021-01-20 02:15:00

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

./script

/usr/bin/script

script

W pierwszy i trzeci sposób $0 nie ma pełnej informacji o ścieżce. W drugim i trzecim pwd nie działa. Jedynym sposobem na uzyskanie katalogu w trzeci sposób byłoby przejście przez ścieżkę i znajdź plik z prawidłowym dopasowaniem. Zasadniczo kod musiałby powtórzyć to, co robi SYSTEM OPERACYJNY.

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

 39
Author: 3 revs, 3 users 73%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
2020-01-18 18:36:47
SCRIPT_DIR=$( cd ${0%/*} && pwd -P )
 35
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
$(dirname "$(readlink -f "$BASH_SOURCE")")
 34
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

To Pobiera bieżący katalog roboczy Mac OS X v10.6.6 ("Snow Leopard"): {]}

DIR=$(cd "$(dirname "$0")"; pwd)
 34
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
2021-01-20 03:43:55

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

SELF=$(readlink /proc/$$/fd/255)
 27
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

Oto jednoelement zgodny z POSIX:

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

# test
echo $SCRIPT_PATH
 23
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

Najkrótszym i najbardziej eleganckim sposobem na to jest:

#!/bin/bash
DIRECTORY=$(cd `dirname $0` && pwd)
echo $DIRECTORY
To działa na wszystkich platformach i jest super czyste.

Więcej szczegółów można znaleźć w " w którym katalogu znajduje się skrypt bash?".

 19
Author: Atul,
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
2020-01-18 18:41:24

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

Również wiele osób zakłada, że uruchamiasz skrypt z powłoki, więc zapominają, gdy otwierasz nowy skrypt, który domyślnie jest w Twoim domu.

Wypróbuj ten katalog dla rozmiaru:

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

To robi to dobrze, niezależnie od tego jak i gdzie go uruchamiasz:

#!/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ć na katalog uruchomionego skryptu:

cd "`dirname "$0"`"
 18
Author: 6 revs, 3 users 73%Mike 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
2021-01-20 03:39:26

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.

 17
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"`
 16
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

Jest to niewielka zmiana rozwiązania e-satis i 3bcdnlklvc04a wskazanego 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.

Zapobiegnie to popd po nieudanym pushd. Dzięki konsolebox.

 16
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
2021-01-20 03:38:07

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
 16
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
2021-01-20 04:10:29

Dla Systemów posiadających GNU coreutils readlink (na przykład Linux):

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

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

 16
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
2021-01-20 04:39:39

$_ 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.

 13
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
2020-01-18 18:45:16

Oto krótkie sposoby na uzyskanie informacji o skrypcie:

Foldery i pliki:

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

Używanie tych poleceń:

    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`

I mam to wyjście:

     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

Zobacz też: https://pastebin.com/J8KjxrPF

 11
Author: User8461,
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
2020-05-15 00:32:46

To działa w Bash 3.2:

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

Jeśli masz katalog ~/bin w swoim $PATH, Masz A wewnątrz tego katalogu. Jest źródłem skryptu ~/bin/lib/B. Wiesz, gdzie dołączony skrypt jest względem oryginalnego, w podkatalogu 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 nazywa skrypt. To zawsze zadziała.

 11
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
2021-01-20 02:43:01

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 primitives, ale nie przeszkadza mi to, ponieważ readlink znacznie upraszcza to zadanie. echo X dodaje X na koniec łańcuch zmiennej tak, że każda końcowa Biała spacja w nazwie pliku nie zostanie zjedzona, a substytucja 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 tworzyć 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"
 11
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
2021-01-20 04:13:28

Spróbuj użyć:

real=$(realpath $(dirname $0))
 10
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

Chyba mam ten. Jestem spóźniona na imprezę, ale myślę, że niektórzy docenią to, że tu są, jeśli 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
 9
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
2020-01-18 18:47:09

Jak uzyskać pełną ścieżkę do pliku, pełny katalog i podstawowa nazwa pliku każdego uruchamianego skryptu

W wielu przypadkach, wszystko, czego potrzebujesz, to pełna ścieżka do skryptu, który właśnie wywołałeś. Można to łatwo osiągnąć za pomocą realpath. Zauważ, że realpath jest częścią GNU coreutils . Jeśli nie masz go już zainstalowanego (domyślnie jest w Ubuntu), możesz go zainstalować za pomocą sudo apt update && sudo apt install coreutils.

Get_script_path.sh:

#!/bin/bash

FULL_PATH_TO_SCRIPT="$(realpath "$0")"

# You can then also get the full path to the directory, and the base
# filename, like this:
SCRIPT_DIRECTORY="$(dirname "$FULL_PATH_TO_SCRIPT")"
SCRIPT_FILENAME="$(basename "$FULL_PATH_TO_SCRIPT")"

# Now print it all out
echo "FULL_PATH_TO_SCRIPT = \"$FULL_PATH_TO_SCRIPT\""
echo "SCRIPT_DIRECTORY    = \"$SCRIPT_DIRECTORY\""
echo "SCRIPT_FILENAME     = \"$SCRIPT_FILENAME\""

Przykładowe wyjście:

~/GS/dev/eRCaGuy_hello_world/bash$ ./get_script_path.sh 
FULL_PATH_TO_SCRIPT = "/home/gabriel/GS/dev/eRCaGuy_hello_world/bash/get_script_path.sh"
SCRIPT_DIRECTORY    = "/home/gabriel/GS/dev/eRCaGuy_hello_world/bash"
SCRIPT_FILENAME     = "get_script_path.sh"

Zauważ, że realpath również pomyślnie przechodzi w dół dowiązań symbolicznych, aby określić i wskazać na ich cele, a nie wskazywać na dowiązanie symboliczne.

Powyższy kod jest teraz częścią mojego eRCaGuy_hello_world repo w tym pliku tutaj: bash/get_script_path.sh .

Bibliografia:

  1. Jak odzyskać ścieżkę bezwzględną podaną relative
 9
Author: Gabriel Staples,
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
2020-12-28 05:32:14

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

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

Ponieważ polecenia takie jak realpath lub readlink mogą być niedostępne (w zależności od systemu operacyjnego).

Uwaga: w Bash zaleca się użycie ${BASH_SOURCE[0]} zamiast $0, w przeciwnym razie ścieżka może się zepsuć podczas pozyskiwania pliku (source/.).

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

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

Ta funkcja przyjmuje jeden argument. Jeśli argument ma już ścieżkę bezwzględną, wypisuje ją taką, jaką jest, w przeciwnym razie print $PWD zmienna + argument filename (bez prefiksu ./).

Powiązane:

 9
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
2021-01-20 04:34:31