Jak najlepiej dołączyć Inne skrypty?
Sposób, w jaki zwykle dołączasz skrypt, to "źródło"
Eg:
Main.sh:
#!/bin/bash
source incl.sh
echo "The main script"
Incl.sh:
echo "The included script"
Wyjście wykonania". /main.sh " jest:
The included script
The main script
... Jeśli spróbujesz wykonać skrypt powłoki z innej lokalizacji, nie będzie on mógł znaleźć include, chyba że znajduje się on w twojej ścieżce.
Jaki jest dobry sposób, aby twój skrypt mógł znaleźć skrypt include, zwłaszcza jeśli na przykład skrypt musi być przenośny?
21 answers
Staram się, aby moje Skrypty były względem siebie. W ten sposób mogę użyć dirname:
#!/bin/sh
my_dir="$(dirname "$0")"
"$my_dir/other_script.sh"
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-05-31 09:21:58
Wiem, że jestem spóźniony na imprezę, ale to powinno działać bez względu na to, jak uruchamiasz skrypt i używasz builtins wyłącznie:
DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
. "$DIR/incl.sh"
. "$DIR/main.sh"
.
(kropka) polecenie jest aliasem do source
, $PWD
jest ścieżką do katalogu roboczego, BASH_SOURCE
jest zmienną array, której członkowie są źródłowymi nazwami plików, ${string%substring}
usuwa najkrótsze dopasowanie $ substring z tyłu $string
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-07 00:47:37
Alternatywa dla:
scriptPath=$(dirname $0)
Jest:
scriptPath=${0%/*}
.. zaletą jest brak zależności od dirname, która nie jest wbudowanym poleceniem (i nie zawsze jest dostępna w emulatorach)
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-10-10 18:18:55
Jeśli znajduje się w tym samym katalogu możesz użyć dirname $0
:
#!/bin/bash
source $(dirname $0)/incl.sh
echo "The main script"
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-10-10 17:17:55
Myślę, że najlepszym sposobem na to jest użycie sposobu Chrisa Borana, ale powinieneś obliczyć MY_DIR w ten sposób:
#!/bin/sh
MY_DIR=$(dirname $(readlink -f $0))
$MY_DIR/other_script.sh
Aby zacytować strony podręcznika dla readlink:
Nigdy nie spotkałem się z przypadkiem użycia, w którym {[2] } nie jest poprawnie obliczony. Jeśli uzyskasz dostęp do skryptu przez dowiązanie symboliczne wreadlink - display value of a symbolic link ... -f, --canonicalize canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist
$PATH
, dział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
2020-06-20 09:12:55
Połączenie odpowiedzi na to pytanie zapewnia najbardziej solidne rozwiązanie.
Pracował dla nas w skryptach klasy produkcyjnej z wielkim wsparciem zależności i struktury katalogów:
#!/bin/bash # Full path of the current script THIS=`readlink -f "${BASH_SOURCE[0]}" 2>/dev/null||echo $0` # The directory where current script resides DIR=`dirname "${THIS}"` # 'Dot' means 'source', i.e. 'include': . "$DIR/compile.sh"
Metoda obsługuje wszystkie z nich:
- spacje w ścieżce
-
Linki (via
readlink
) -
${BASH_SOURCE[0]}
jest bardziej wytrzymały niż$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
2018-10-01 14:58:16
SRC=$(cd $(dirname "$0"); pwd)
source "${SRC}/incl.sh"
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
2009-06-14 13:35:36
To działa nawet jeśli skrypt jest pozyskiwany:
source "$( dirname "${BASH_SOURCE[0]}" )/incl.sh"
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-08-12 09:08:28
1. Neatest
Zbadałem prawie każdą sugestię i oto najbardziej zgrabna, która dla mnie zadziałała:
script_root=$(dirname $(readlink -f $0))
Działa nawet wtedy, gdy skrypt jest dowiązany symbolicznie do katalogu $PATH
.
Zobacz go w akcji tutaj: https://github.com/pendashteh/hcagent/blob/master/bin/hcagent
2. Najfajniejsze
# Copyright https://stackoverflow.com/a/13222994/257479
script_root=$(ls -l /proc/$$/fd | grep "255 ->" | sed -e 's/^.\+-> //')
To właściwie z innej odpowiedzi na tej stronie, ale dodaję ją również do mojej odpowiedzi!
2. Najbardziej niezawodny
Alternatywnie, w rzadkich przypadkach, że te nie zadziałały, oto podejście bullet proof:
# Copyright http://stackoverflow.com/a/7400673/257479
myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); }
whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; }
whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; }
script_root=$(dirname $(whereis_realpath "$0"))
Możesz zobaczyć go w akcji w taskrunner
Źródło: https://github.com/pendashteh/taskrunner/blob/master/bin/taskrunner
Mam nadzieję, że to komuś pomoże :)
Również, proszę zostawić to jako komentarz, jeśli jeden nie działa dla Ciebie i wspomnieć o systemie operacyjnym i emulator. Dzię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
2020-06-20 09:12:55
Musisz określić lokalizację innych skryptów, nie ma innego sposobu na obejście tego. Polecam konfigurowalną zmienną u góry skryptu:
#!/bin/bash
installpath=/where/your/scripts/are
. $installpath/incl.sh
echo "The main script"
Alternatywnie, możesz nalegać, aby użytkownik utrzymywał zmienną środowiskową wskazującą, gdzie znajduje się twój program home, jak PROG_HOME lub somesuch. Można to podać użytkownikowi automatycznie, tworząc skrypt z tą informacją w /etc / profile.d/ , które będą pozyskiwane za każdym razem, gdy użytkownik zaloguje się.
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-10-10 17:32:52
Sugerowałbym utworzenie skryptu setenv, którego jedynym celem jest dostarczenie lokalizacji dla różnych komponentów w całym systemie.
Wszystkie Inne skrypty będą źródłem tego skryptu tak, że wszystkie lokalizacje są wspólne dla wszystkich skryptów korzystających ze skryptu setenv.
Jest to bardzo przydatne podczas uruchamiania cronjobs. Dostajesz Minimalne środowisko podczas uruchamiania crona, ale jeśli wszystkie skrypty crona zawierają najpierw skrypt setenv, możesz kontrolować i synchronizować środowisko, w którym chcesz wykonać cronjobs.
Zastosowaliśmy taką technikę na naszej małpie konstrukcyjnej, która była używana do ciągłej integracji w całym projekcie około 2000 kSLOC.
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-10-10 17:18:51
ODPOWIEDŹ Steve ' a jest zdecydowanie prawidłową techniką, ale powinna być zrefakturowana tak, aby zmienna installpath znajdowała się w osobnym skrypcie środowiskowym, w którym wszystkie takie deklaracje są dokonywane.
Wtedy wszystkie skrypty źródłowe tego skryptu i powinny się zmienić installpath, wystarczy zmienić go tylko w jednym miejscu. Sprawia, że rzeczy są bardziej przyszłościowe. Boże, nienawidzę tego słowa! (-:
BTW naprawdę powinieneś odnieść się do zmiennej używając ${installpath}, gdy używasz jej w sposób pokazany w Twoim przykład:
. ${installpath}/incl.sh
Jeśli szelki zostaną pominięte, niektóre powłoki spróbują rozwinąć zmienną "installpath/incl.sh"!
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-10-11 11:35:12
Shell Script Loader to moje rozwiązanie.
Zapewnia funkcję o nazwie include (), która może być wywołana wiele razy w wielu skryptach w celu odwołania się do jednego skryptu, ale ładuje skrypt tylko raz. Funkcja może przyjmować pełne ścieżki lub częściowe ścieżki (skrypt jest przeszukiwany w ścieżce wyszukiwania). Dostarczona jest również podobna funkcja load (), która bezwarunkowo ładuje Skrypty.
To działa dla bash, ksh, pd ksh i zsh z zoptymalizowane skrypty dla każdego z nich; i inne powłoki, które są ogólnie kompatybilne z oryginalnym SH jak ash, dash, heirloom sh , itp., poprzez uniwersalny skrypt, który automatycznie optymalizuje swoje funkcje w zależności od funkcji, jakie może zapewnić powłoka.
[Fowarded przykład]
Start.sh
Jest to opcjonalny skrypt startowy. Umieszczenie tutaj metod uruchamiania jest tylko wygodą i może być umieszczony w skrypcie głównym. Ten skrypt nie jest również potrzebny, jeśli skrypty mają być skompilowane.
#!/bin/sh
# load loader.sh
. loader.sh
# include directories to search path
loader_addpath /usr/lib/sh deps source
# load main script
load main.sh
Main.sh
include a.sh
include b.sh
echo '---- main.sh ----'
# remove loader from shellspace since
# we no longer need it
loader_finish
# main procedures go from here
# ...
A.sh
include main.sh
include a.sh
include b.sh
echo '---- a.sh ----'
B.sh
include main.sh
include a.sh
include b.sh
echo '---- b.sh ----'
Wyjście:
---- b.sh ----
---- a.sh ----
---- main.sh ----
Najlepsze jest to, że skrypty bazujące na nim mogą być również skompilowane w jeden skrypt z dostępnym kompilatorem.
Oto projekt, który go używa: http://sourceforge.net/p/playshell/code/ci/master/tree / . It może działać przenośnie z kompilacją skryptów lub bez niej. Kompilacja w celu wytworzenia pojedynczego skryptu może się również zdarzyć i jest pomocna podczas instalacji.
Stworzyłem również prostszy prototyp dla każdej Partii Konserwatywnej, która może chcieć mieć krótkie pojęcie o tym, jak działa skrypt implementacyjny: https://sourceforge.net/p/loader/code/ci/base/tree/loader-include-prototype.bash . jest mały i każdy może po prostu umieścić kod w swoim skrypcie głównym, jeśli chce, jeśli jego kod jest przeznaczony do uruchomienia z Bash 4.0 lub nowszym, a także nie używa eval
.
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-06-28 17:29:48
Osobiście umieść wszystkie biblioteki w folderze lib
i użyj funkcji import
, aby je załadować.
struktura folderów
script.sh
spis treści
# Imports '.sh' files from 'lib' directory
function import()
{
local file="./lib/$1.sh"
local error="\e[31mError: \e[0mCannot find \e[1m$1\e[0m library at: \e[2m$file\e[0m"
if [ -f "$file" ]; then
source "$file"
if [ -z $IMPORTED ]; then
echo -e $error
exit 1
fi
else
echo -e $error
exit 1
fi
}
Zauważ, że ta funkcja importu powinna znajdować się na początku skryptu, a następnie możesz łatwo zaimportować swoje biblioteki w następujący sposób:
import "utils"
import "requirements"
Dodaj pojedynczą linię u góry każdej biblioteki (np. utils.sh):
IMPORTED="$BASH_SOURCE"
Teraz masz dostęp do funkcji wewnątrz utils.sh
i requirements.sh
od script.sh
TODO: napisz linker, aby zbudować pojedynczy sh
plik
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-08-10 09:36:27
Użycie source lub $0 nie da ci prawdziwej ścieżki skryptu. Możesz użyć ID procesu skryptu, aby pobrać jego prawdziwą ścieżkę
ls -l /proc/$$/fd |
grep "255 ->" |
sed -e 's/^.\+-> //'
Używam tego skryptu i zawsze mi dobrze służył:)
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-04 22:26:10
Umieściłem wszystkie moje skrypty startowe w .bashrc.katalog D. Jest to powszechna technika w takich miejscach jak /etc / profile.d, itp.
while read file; do source "${file}"; done <<HERE
$(find ${HOME}/.bashrc.d -type f)
HERE
Problem z rozwiązaniem za pomocą globbingu...
for file in ${HOME}/.bashrc.d/*.sh; do source ${file};done
...możesz mieć listę plików, która jest "zbyt długa". Takie podejście...
find ${HOME}/.bashrc.d -type f | while read file; do source ${file}; done
...działa, ale nie zmienia środowiska zgodnie z życzeniem.
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-06-13 22:33:19
Oczywiście, dla każdego ich własnych, ale myślę, że blok poniżej jest dość solidny. Uważam, że wiąże się to z "najlepszym" sposobem znalezienia katalogu i "najlepszym" sposobem wywołania innego skryptu bash:
scriptdir=`dirname "$BASH_SOURCE"`
source $scriptdir/incl.sh
echo "The main script"
Więc może to być "najlepszy" sposób na dołączenie innych skryptów. Jest to oparte na innej "najlepszej" odpowiedzi, która mówi skryptowi bash, gdzie jest przechowywany
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 12:34:45
To powinno działać niezawodnie:
source_relative() {
local dir="${BASH_SOURCE%/*}"
[[ -z "$dir" ]] && dir="$PWD"
source "$dir/$1"
}
source_relative incl.sh
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-06-04 21:22:43
Musimy tylko znaleźć folder, w którym nasz incl.sh oraz main.sh jest przechowywany; wystarczy zmienić swoje main.sh z tym:
Main.sh
#!/bin/bash
SCRIPT_NAME=$(basename $0)
SCRIPT_DIR="$(echo $0| sed "s/$SCRIPT_NAME//g")"
source $SCRIPT_DIR/incl.sh
echo "The main script"
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-01-16 13:35:51
Według man hier
odpowiednie miejsce dla Script includes to /usr/local/lib/
/usr / local / lib
Pliki związane z lokalnie zainstalowanymi programami.
Osobiście wolę /usr/local/lib/bash/includes
dla includes.
Istnieje bash-helper lib do włączania bibliotek w ten sposób:
#!/bin/bash
. /usr/local/lib/bash/includes/bash-helpers.sh
include api-client || exit 1 # include shared functions
include mysql-status/query-builder || exit 1 # include script functions
# include script functions with status message
include mysql-status/process-checker; status 'process-checker' $? || exit 1
include mysql-status/nonexists; status 'nonexists' $? || exit 1
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
2019-08-04 13:01:05
Możesz również użyć:
PWD=$(pwd)
source "$PWD/inc.sh"
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-11-19 16:13:32