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
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!
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'
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
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
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.
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.
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
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?
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
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.
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.
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 )
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")")
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)
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)
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
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?".
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"`"
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 GNUcoreutils
i zastąpić togreadlink -f
.I oczywiście
dirname
pobiera Katalog nadrzędny ścieżki.
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"`
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.
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
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.
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.
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
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.
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"
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))
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
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:
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:
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