Chciałbym przekazać parametry do skryptu bash w stylu dd. Zasadniczo chcę
./script a=1 b=43
mieć taki sam efekt jak
a=1 b=43 ./script
Myślałem, że mogę to osiągnąć za pomocą:
for arg in "$@"; do
eval "$arg";
done
Jaki jest dobry sposób na zapewnienie eval
bezpieczeństwa, tzn. Że "$arg"
odpowiada statycznemu (bez wykonywania kodu), przypisaniu zmiennej?
Czy jest na to lepszy sposób? (Chciałbym, żeby to było proste).
=
separatorem i wykonać zadanie z bardziej starannie skonstruowanym eval. Dla bezpieczeństwa, do prywatnego użytku, zrobiłbym to tak, jak ty to zrobiłeś.Odpowiedzi:
Możesz to zrobić w bashu bez eval (i bez sztucznego ucieczki):
Edycja: Na podstawie komentarza Stéphane'a Chazelasa dodałem flagi do deklaracji, aby uniknąć przypisania zmiennej już zadeklarowanej jako zmienna tablicowa lub całkowita, co pozwoli uniknąć szeregu przypadków, w których
declare
wartość częścikey=val
argumentu będzie oceniana . (+a
Spowoduje błąd, jeśli zmienna, która ma zostać ustawiona, jest już zadeklarowana na przykład jako zmienna tablicowa.) Wszystkie te luki dotyczą użycia tej składni do ponownego przypisania istniejących zmiennych (tablica lub liczba całkowita), które zwykle byłyby dobrze znane zmienne powłoki.W rzeczywistości jest to tylko przypadek klasy ataków iniekcyjnych, które będą w równym stopniu wpływać na
eval
rozwiązania oparte na rozwiązaniach: naprawdę byłoby znacznie lepiej zezwolić tylko na znane nazwy argumentów niż na ślepo ustawić dowolną zmienną, która pojawiła się w wierszu poleceń. (Zastanów się, co się stanie, jeśliPATH
na przykład wiersz polecenia zostanie ustawiony . Lub zresetuje się,PS1
aby uwzględnić ocenę, która nastąpi przy następnym wyświetleniu monitu).Zamiast używać zmiennych bash, wolałbym użyć tablicy asocjacyjnej nazwanych argumentów, która jest łatwiejsza do ustawienia i znacznie bezpieczniejsza. Alternatywnie może ustawić rzeczywiste zmienne bash, ale tylko wtedy, gdy ich nazwy znajdują się w tablicy asocjacyjnej uzasadnionych argumentów.
Jako przykład tego drugiego podejścia:
źródło
^[[:alpha:]_][[:alnum:]_]*=
?foo=
to jedyny sposób, aby ustawić foo na pusty ciąg, więc powinno być dozwolone (IMHO). Naprawiłem wsporniki, dzięki.declare
jest tak niebezpieczny jakeval
(można nawet powiedzieć gorzej, ponieważ nie jest tak oczywiste, że jest tak niebezpieczny). Spróbuj na przykład nazwać to'DIRSTACK=($(echo rm -rf ~))'
argumentem.+x
is „not-x
”.-a
= tablica indeksowana,-A
= tablica asocjacyjna,-i
= zmienna całkowita. Zatem: tablica nieindeksowana, tablica asocjacyjna, liczba całkowita.bash
może być konieczne dodanie,+c
aby wyłączyć zmienne złożone lub+F
wyłączyć zmienne zmienne. Nadal używałbymeval
tam, gdzie wiesz, gdzie stoisz.POSIX jeden (zestawy
$<prefix>var
zamiast$var
problemów uniknąć specjalnymi zmiennymi podobaIFS
/PATH
...):Nazywany jako
myscript x=1 PATH=/tmp/evil %=3 blah '=foo' 1=2
, przypisuje:źródło
Rozwiązanie lcd047 refaktoryzowane z
DD_OPT_
prefiksem na stałe :frostschutz zasługuje na uznanie za większość refaktoryzacji.
Umieszczam to w pliku źródłowym jako zmienną globalną:
eval "$DD_OPTS_PARSE"
robi całą magię.Wersja dla funkcji to:
DD_OPTS_PARSE_LOCAL="${PARSE_AND_REMOVE_DD_OPTS/DD_OPT_/local DD_OPT_}"
W użyciu:
eval "$DD_OPTS_PARSE_LOCAL"
Zrobiłem z tego repo , wraz z testami i README.md. Następnie użyłem tego w opakowującym interfejsie API Github API, które pisałem, i użyłem tego samego opakowania, aby skonfigurować klon github wspomnianego repozytorium (ładowanie jest fajne).
Bezpieczne przekazywanie parametrów dla skryptów bash w jednym wierszu. Cieszyć się. :)
źródło
*=*
i przestać zastępować klucz / val tam, gdzie nie ma =. (ponieważ refaktoryzowałeś): Pkey
ival
, i po prostu pisaćeval "${1%%=*}"=\${1#*=}
. Ale to tak daleko, jak to możliwe,eval "$1"
ponieważ w @ ricideclare "$arg"
nie będzie oczywiście działać. Uważaj też na ustawianie takich rzeczy jakPATH
lubPS1
.case
. Prawdopodobnie to nie ma znaczenia, ale na wypadek, gdybyś nie wiedział ...Obsługiwana jest klasyczna skorupa Bourne'a, a skorupa Bash i Korn nadal obsługują
-k
opcję. Gdy ma to zastosowanie, wszelkie „dd
podobne” opcje polecenia w dowolnym miejscu wiersza poleceń są automatycznie konwertowane na zmienne środowiskowe przekazywane do polecenia:Nieco trudniej jest przekonać, że są to zmienne środowiskowe; uruchomienie tego działa dla mnie:
Pierwszy
env | grep
pokazuje brak zmiennych środowiskowych z pojedynczą małą literą. Pierwszybash
pokazuje, że do skryptu nie są przekazywane argumenty-c
, a środowisko zawiera trzy jednoliterowe zmienne.set +k
Anuluje-k
i pokazuje, że ta sama komenda ma teraz argumenty przekazywane do niej. (a=1
Traktowano to jak$0
scenariusz; można to również udowodnić za pomocą odpowiedniego echa).Uzyskuje się to, o co pyta pytanie - pisanie
./script.sh a=1 b=2
powinno być takie samo jak pisaniea=1 b=2 ./script.sh
.Pamiętaj, że napotkasz problemy, jeśli wypróbujesz takie sztuczki w skrypcie:
"$@"
Traktuje dosłownie; nie jest ponownie analizowany w celu znalezienia zmiennych w stylu przypisania (zarówno w, jakbash
iksh
). Próbowałem:i tylko
already_invoked_with_minus_k
zmienna środowiskowa jest ustawiona wexec
skrypcie 'd.źródło
Moja próba:
Działa z (prawie) arbitralnymi śmieciami na RHS:
źródło
shift
zamiastshift 1
). W przeciwnym razie dzięki!Jakiś czas temu zdecydowałem się
alias
na tego rodzaju pracę. Oto moja kolejna odpowiedź:Czasami jednak możliwe jest rozdzielenie oceny i wykonania takich oświadczeń. Na przykład
alias
można użyć do wstępnej oceny polecenia. W poniższym przykładzie definicja zmiennej jest zapisywana w aliasie, który można pomyślnie zadeklarować tylko wtedy, gdy$var
oceniana zmienna nie zawiera bajtów, które nie pasują do znaków alfanumerycznych ASCII lub _.eval
służy tutaj do obsługi wywoływania nowegoalias
z kontekstu cytowanej nazwy zmiennej - nie do przypisania dokładnie. Ieval
w ogóle wywoływany jest tylko wtedy, gdy poprzedniaalias
definicja się powiedzie, i chociaż wiem, że wiele różnych implementacji zaakceptuje wiele różnych rodzajów nazw aliasów, nie znalazłem jeszcze powłoki, która zaakceptuje całkowicie pustą .Definicja w aliasie ma
_$var
jednak na celu zapewnienie, że żadne znaczące wartości środowiska nie zostaną zapisane. Nie znam żadnych wartych uwagi wartości środowiskowych zaczynających się od _ i zwykle jest to bezpieczny zakład na deklarację półprywatną.W każdym razie, jeśli definicja aliasu zakończy się powodzeniem, zadeklaruje alias nazwany na
$var
wartość. Ieval
wywoła to tylko,alias
jeśli również nie zaczyna się od liczby - w przeciwnym razieeval
dostaje tylko zerowy argument. Jeśli więc oba warunki są spełnione,eval
wywoływana jestalias
i zapisywanaalias
jest definicja zmiennej , po czym nowy alias jest natychmiast usuwany z tabeli skrótów.W
alias
tym kontekście przydatne jest również to, że możesz wydrukować swoją pracę. po zapytaniualias
wydrukuje podwójnie cytowane oświadczenie o bezpiecznej wymianie powłoki .WYNIK
źródło