Mam funkcję bash, aby ustawić w $PATH
ten sposób -
assign-path()
{
str=$1
# if the $PATH is empty, assign it directly.
if [ -z $PATH ]; then
PATH=$str;
# if the $PATH does not contain the substring, append it with ':'.
elif [[ $PATH != *$str* ]]; then
PATH=$PATH:$str;
fi
}
Ale problem polega na tym, że muszę napisać inną funkcję dla różnych zmiennych (na przykład inną funkcję dla $CLASSPATH
podobnych assign-classpath()
itp.). Nie mogłem znaleźć sposobu na przekazanie argumentu do funkcji bash, aby móc uzyskać do niej dostęp przez odniesienie.
Byłoby lepiej, gdybym miał coś takiego -
assign( bigstr, substr )
{
if [ -z bigstr ]; then
bigstr=substr;
elif [[ bigstr != *str* ]]; then
bigstr=bigstr:substr;
fi
}
Każdy pomysł, jak osiągnąć coś takiego jak wyżej w bash?
bash
bash-script
ramgorur
źródło
źródło
assign-path /abc
nie dołączy/abc
do PATH jeśli $ PATH zawiera już/abc/def
,/abcd
,/def/abc
itd. Szczególnie nie można dodać/bin
, jeśli PATH zawiera już/usr/bin
.$PATH
i anulować sprawdzian przed swoimi argumentami jak:add=/bin dir=/usr/bin ; [ -z "${dir%"$add"}" ] || dir="${dir}:${add}"
. W mojej odpowiedzi robię to w ten sposób, używając tylu argumentów, ile tylko chceszIFS=:
.$PATH
? i Dodaj katalog do,$PATH
jeśli jeszcze go nie ma (w trybie Super User ).Odpowiedzi:
W
bash
możesz użyć${!varname}
do rozwinięcia zmiennej, do której odwołuje się zawartość innej. Na przykład:Ze strony podręcznika:
Ponadto, aby ustawić zmienną, do której odwołuje się zawartość (bez niebezpieczeństw
eval
), możesz użyćdeclare
. Na przykład:Tak więc możesz napisać swoją funkcję w ten sposób (uważaj, ponieważ jeśli używasz
declare
w funkcji, musisz dać-g
lub zmienna będzie lokalna):I używaj go w następujący sposób:
Zauważ, że poprawiłem również błąd, w którym jeśli
substr
jest już podciągiem jednego z członków oddzielonych dwukropkamibigstr
, ale nie jest jego własnym członkiem, wówczas nie zostanie dodany. Na przykład pozwoliłoby to na dodanie/bin
doPATH
zmiennej już zawierającej/usr/bin
. Używaextglob
zestawów, aby dopasować początek / koniec łańcucha lub dwukropek, a następnie cokolwiek innego. Bezextglob
tego alternatywą byłoby:źródło
-g
indeclare
nie jest dostępny w starszej wersji bash, czy jest jakiś sposób, aby uczynić to wstecznym kompatybilnym?export
aby umieścić go w swoim środowisku (na ryzyko zastąpienia czegoś ważnego) lubeval
(różne problemy, w tym bezpieczeństwo, jeśli nie jesteś ostrożny). Jeśli używaszeval
, powinieneś być w porządku, jeśli robisz to takeval "$target=\$substr"
. Jeśli jednak zapomnisz\
, potencjalnie wykona polecenie, jeśli w treści jest spacjasubstr
.Nowy w bash 4.3, jest
-n
opcjadeclare
&local
:To się drukuje
hello, world
.źródło
Możesz użyć
eval
do ustawienia parametru. Opis tego polecenia można znaleźć tutaj . Następujące użycieeval
jest nieprawidłowe:W odniesieniu do dodatkowej oceny
eval
należy skorzystaćSprawdź wyniki korzystania z tych funkcji:
Ale możesz osiągnąć swój cel bez użycia
eval
. Wolę ten sposób, który jest prostszy.Poniższa funkcja sprawia, że podstawienie we właściwy sposób (mam nadzieję)
Sprawdź następujące dane wyjściowe
Teraz możesz użyć
augment
funkcji w następujący sposób, aby ustawić zmienną:źródło
v='echo "OHNO!" ; var' ; l=val ; eval $v='$l'
- echo „OHNO!” Przed przypisaniem var. Możesz „$ {v ## * [;„ $ IFS ”]}} =„ $ l ””, aby upewnić się, że łańcuch nie może rozwinąć się do niczego, co nie będzie oceniane za pomocą =.=
przypisania. Możesz argumentować, że mój skrypt nie sprawdza swojego argumentu. To prawda. Nawet nie sprawdzam, czy jest jakiś argument lub czy liczba argumentów jest poprawna. Ale było to zamierzone. OP może dodać takie kontrole, jeśli chce.v
(lepiej jej wartości) jako drugiego argumentu funkcji przypisania. Dlatego jego wartość powinna znajdować się po prawej stronie zadania. Konieczne jest zacytowanie argumentu funkcjiassign
. Dodałem tę subtelność do mojego posta.Za pomocą kilku sztuczek możesz przekazać nazwane parametry do funkcji wraz z tablicami (testowane w bash 3 i 4).
Opracowana przeze mnie metoda umożliwia dostęp do parametrów przekazywanych do funkcji takiej jak ta:
Innymi słowy, nie tylko możesz wywoływać swoje parametry według ich nazw (co stanowi bardziej czytelny rdzeń), możesz faktycznie przekazywać tablice (i odniesienia do zmiennych - ta funkcja działa jednak tylko w bash 4.3)! Ponadto wszystkie zmapowane zmienne są w zasięgu lokalnym, podobnie jak 1 USD (i inne).
Kod, który sprawia, że ta praca jest dość lekka i działa zarówno w bash 3, jak i bash 4 (to jedyne wersje, z którymi go testowałem). Jeśli interesuje Cię więcej takich sztuczek, które sprawiają, że programowanie w bash jest znacznie przyjemniejsze i łatwiejsze, możesz rzucić okiem na moją platformę Bash Infinity Framework , poniższy kod został opracowany w tym celu.
źródło
Czy to pasuje?
źródło
eval
jest podatne na wykonanie dowolnego polecenia.eval
linie Zhe były bezpieczniejsze? Zwykle, kiedy myślę, że potrzebuję eval, postanawiam nie używać * sh i zamiast tego przełączać się na inny język. Z drugiej strony, używając tego w skryptach, aby dołączyć wpisy do niektórych zmiennych podobnych do ŚCIEŻKI, będzie działać ze stałymi ciągami, a nieeval
bezpiecznie - ale to wymaga dużo myślenia. Jeśli próbujesz tylko odwołać się do parametru, chciałbyś zrobić coś takiego: weval "$1=\"\$2\""
ten sposób przyeval's
pierwszym przejściu ocenia tylko 1 $, a przy drugim wartość = "2 $". Ale musisz zrobić coś innego - tutaj nie jest to konieczne."${1##*[;"$IFS"]}=\"\$2\""
- i nawet to nie ma gwarancji. Lubeval "$(set -- $1 ; shift $(($#-1)) ; echo $1)=\"\$2\""
. To nie jest łatwe.Nazwane argumenty po prostu nie są tym, jak zaprojektowano składnię Basha. Bash został zaprojektowany jako iteracyjne ulepszenie powłoki Bourne'a. Jako taki musi zapewnić, że pewne rzeczy działają między dwiema skorupami tak bardzo, jak to możliwe. Nie jest to więc łatwe do pisania skryptami, ale po prostu lepsze niż Bourne, przy jednoczesnym zapewnieniu, że przeniesienie skryptu ze środowiska Bourne
bash
jest tak proste, jak to możliwe. Nie jest to trywialne, ponieważ wiele pocisków wciąż traktuje Bourne'a jako de facto standard. Ponieważ ludzie piszą swoje skrypty, aby były kompatybilne z Bourne (dla tej przenośności), potrzeba ta pozostaje w mocy i jest mało prawdopodobne, aby się kiedykolwiek zmieniła.Prawdopodobnie lepiej spojrzeć na inny skrypt powłoki (jak
python
coś lub coś) całkowicie, jeśli jest to w ogóle wykonalne. Jeśli napotykasz ograniczenia związane z językiem, musisz zacząć używać nowego języka.źródło
bash
życia to była prawda. Ale teraz wprowadzono szczegółowe przepisy. Pełne zmienne odniesienia są teraz dostępne wbash 4.3
- patrz odpowiedź deroberta .Przy standardowej
sh
składni (działałbybash
i nie tylkobash
) można wykonać:Podobnie jak w przypadku rozwiązania z użyciem
bash
„sdeclare
, jest bezpieczny , o ile$1
zawiera poprawną nazwę zmiennej.źródło
NA NAZWANYCH ARGACH:
Jest to bardzo proste i
bash
wcale nie jest wymagane - jest to podstawowe zachowanie przypisania określone przez POSIX poprzez rozszerzenie parametrów:Aby demonstrować w sposób podobny do @Graeme, ale w przenośny sposób:
I robię to tylko,
str=
aby upewnić się, że ma wartość zerową, ponieważ rozszerzenie parametru ma wbudowane zabezpieczenie przed ponownym przypisaniem środowiska powłoki, jeśli jest już ustawione.ROZWIĄZANIE:
W przypadku konkretnego problemu nie uważam, że nazwane argumenty są konieczne, choć z pewnością są możliwe.
$IFS
Zamiast tego użyj :Oto, co dostaję, kiedy go uruchomię:
Zauważ, że dodało tylko argumenty, których jeszcze nie było
$PATH
lub które pojawiły się wcześniej? A może nawet że wymagało to więcej niż jednego argumentu?$IFS
jest przydatny.źródło
assign
tutaj. Jeśli masz pytania dotyczące tego, jak to działa, chętnie odpowiem. A tak przy okazji, jeśli naprawdę chcesz nazwanych argumentów, możesz spojrzeć na moją inną odpowiedź, w której pokazuję, jak zadeklarować funkcję nazwaną dla argumentów innej funkcji: unix.stackexchange.com/a/120531/52934Nie mogę znaleźć czegoś takiego jak rubin, python itp., Ale to jest mi bliższe
Moim zdaniem czytelność jest lepsza, 4 linie są zbyt duże, aby zadeklarować nazwy parametrów. Wygląda też bliżej współczesnych języków.
źródło
a=$1 b=$2 ...
działa równie dobrze.