Czy nazwa zmiennej powłoki może zawierać łącznik lub myślnik (-)?

38

Nie jestem w stanie używać -zmiennych w powłoce. Czy istnieje sposób, aby móc go używać, ponieważ mam jeden skrypt, który zależy od takich nazwanych zmiennych:

$export a-b=c
-bash: export: `a-b=c': not a valid identifier

$export a_b=c

Pierwszy rzuca podany błąd, a drugi działa dobrze.

xyz
źródło
możliwy duplikat witryny: stackoverflow.com/questions/2821043/...
Ciro Santilli 21 改造 中心 法轮功 六四 事件
Powłoki zwykle nie pozwalają na takie nazwy zmiennych. Musiałbyś ominąć powłokę, być może nawet przy użyciu niestandardowego programu C ładującego zmienne do środowiska twojej komendy. Czy nie możesz naprawić tej nieprawidłowości (nawet możliwego ryzyka związanego z bezpieczeństwem)?
vonbrand

Odpowiedzi:

47

Nigdy nie spotkałem powłoki w stylu Bourne'a, która dopuszczała -zmienną nazwę. _Obsługiwane są tylko litery ASCII (w obu przypadkach) i cyfry, a pierwszy znak nie może być cyfrą.

Jeśli masz program, który wymaga zmiennej środowiskowej, która nie odpowiada ograniczeniom powłoki, uruchom ją z envprogramem.

env 'strange-name=some value' myprogram

Zauważ, że niektóre powłoki (np. Nowoczesne myślniki , mksh, zsh) usuwają zmienne, których nazw nie lubią ze środowiska. ( Shellshock spowodował, że ludzie są bardziej ostrożni w kwestii nazw zmiennych środowiskowych, więc ograniczenia mogą z czasem stać się bardziej rygorystyczne, a nie bardziej liberalne.) Jeśli więc chcesz przekazać zmienną, której nazwa zawiera znak specjalny do programu, przekaż ją bezpośrednio, bez powłoki pośredniej ( env 'strange-name=some value' sh -c'…; myprogram'może lub nie może działać).

Gilles „SO- przestań być zły”
źródło
Nie działa.
Jesse Glick,
4
@JesseGlick Tak to robi. (Twój komentarz byłby użyteczny, gdybyś zdefiniował „nie działa”: z jakimi danymi? Jaki jest efekt zamiast pożądanego efektu? I jeśli powiedziałeś, która implementacja została envużyta w jakim systemie operacyjnym.)
SO Gilles przestał być zło '
Przepraszam. Ubuntu Yakkety ze wszystkimi aktualizacjami, envod coreutils, shz dash: env 'with-dashes=value' bash -c 'env | fgrep dashes'działa, ale env 'with-dashes=value' sh -c 'env | fgrep dashes'nic nie drukuje. To znaczy, envsamo w sobie jest w porządku, ale Dash wydaje się specjalnie blokować te zmienne. Zatem jeśli dany program jest uruchamiany przez opakowanie powłoki z typowym #!/bin/shnagłówkiem, nie ma widocznego sposobu na przekazanie takich zmiennych. przykładowe obejście
Jesse Glick
@JesseGlick To kreska usuwająca zmienną. Musisz użyć envbliżej strony wywołującej programu, która potrzebuje tej nazwy zmiennej, bez powłoki między nimi. Dash nie jest sam w usuwaniu zmiennych, których nazwom się nie podoba.
Gilles 'SO - przestań być zły'
1
@JesseGlick Prawdą jest, że niektóre rzeczy, które kiedyś działały, mogą już nie działać: od czasu szoku , ludzie stali się bardziej konserwatywni w kwestii nazw zmiennych, a myśl zmieniła się, odkąd napisałem tę odpowiedź (choć nie w wyniku Shellshocka, ale aby uniknąć błędu w tym samym stylu). Dodałem notatkę do mojej odpowiedzi.
Gilles 'SO - przestań być zły'
15

W Bash nie jest to możliwe.

Z sekcji Definicje na stronie podręcznika bash:

nazwa Słowo składające się wyłącznie ze znaków alfanumerycznych i znaków podkreślenia, rozpoczynające się od znaku alfabetu lub znaku podkreślenia. Nazywany również identyfikatorem.

Z sekcji Parametry na stronie podręcznika bash:

Parametr to jednostka przechowująca wartości. Może to być nazwa, liczba lub jeden ze znaków specjalnych wymienionych poniżej w części Parametry specjalne. Zmienna jest parametrem oznaczonym nazwą.

Lekensteyn
źródło
2
+1 za
ponowne
2
Stary post, który znam, ale chcę podkreślić, że dla początkujących strony podręcznika man mogą być dość tajemnicze. Nadal mam czas, kiedy potrzebuję polować na lepsze wyjaśnienia / przykłady. Każdy by kłamał, gdyby powiedział, że nigdy im się to nie przydarzyło.
TCZ8,
1
@ TCZ8 Jedyni ludzie, którzy powiedzieli mi, że uważali strony man za „tajemnicze”, to ci sami ludzie, którzy nie czytają komunikatów o błędach i po prostu przeglądają wszystko, pomijając to, co muszą przeczytać.
Miles Rout
13

Możesz uzyskać dostęp do zmiennej dzielonej za pomocą odwołania pośredniego.

$ env 'my-hyphenated-variable=hello' /bin/bash
$ name='my-hyphenated-variable'
$ echo ${!name}
hello
Jon Nalley
źródło
1
Nigdy nie słyszałem o tej funkcjonalności, dopóki nie przeczytałem tego komentarza. Dostarczyłem znacznie łatwiejszego rozwiązania niż zaakceptowana odpowiedź.
DrStrangepork
7
To zachowanie zostało wyłączone w nowszych wersjach bash. Zobacz stackoverflow.com/questions/36989263/... do gruntownej analizy sytuacji.
Nicolas Dudebout,
6

Jeśli twój skrypt zależy od tego, czy nazwy zmiennych mają łączniki, jest to błąd programowania. Jeśli jest to dla ciebie wygodne ze względu na narzędzia, których regularnie używasz, aby nazwy zmiennych zawierały myślnik, być może będziesz musiał nauczyć się więcej i różnych narzędzi.

Czy próbowałeś użyć tr do konwersji myślników na podkreślenia?

hyphenated_name="a-b"
unhyphenated_name=$(echo $hyphenated_name | tr '-' '_')
declare -x $unhyphenated_name="some value"

Bash pozwala na pojawienie się „-” w nazwach funkcji. Robię to cały czas. Na przykład:

function foo-bar() {
   echo "$@"
}
Brian J. Fox
źródło
2

Znak dash ( -) jest znakiem przerwania i nie jest dozwolony jako część nazw zmiennych. Istnieją sposoby na zhackowanie tego przy użyciu zmiennych cytowanych, ale ich analiza jest naprawdę problematyczna. Istnieją również inne znaki o specjalnym znaczeniu w kontekście nazw zmiennych w bash, w szczególności nawiasy klamrowe, nawiasy, znaki operatora i cudzysłowy. (np. {}()=+-&'"i więcej)

Sugerowałbym, że praktycznie musisz znaleźć inny paradygmat, na którym zbudujesz swój skrypt. Być może wiesz z innych języków o „nazwach zmiennych zmiennych”. Zasadniczo nie jest to dobry pomysł w skryptach powłoki.

Jeśli edytujesz to lub zadajesz nowe pytanie ze szczegółami swojego kontekstu i tego, co próbujesz osiągnąć, możemy zaproponować dobry sposób na napisanie skryptu.

Caleb
źródło
2

Podręcznik Bash definiuje „nazwę” jako:

„Słowo” składające się wyłącznie z liter, cyfr i znaków podkreślenia i rozpoczynające się od litery lub znaku podkreślenia. „Nazwy są używane jako nazwy zmiennych powłoki i nazwy funkcji. Nazywany również „identyfikatorem”.

Nie możesz więc używać myślnika w nazwie.

Michael Hoffman
źródło
0

Większość powłok obsługuje tylko zmienne az, AZ, 0-9 i _ dla nazw zmiennych. Przeczytaj drugi element na tej stronie .


źródło
0

Możesz grać z env i sed.

Jako przykład musiałem odczytać zmienną „ELASTICSEARCH_CLUSTER-NODES”.
Komenda env wyświetla następujące dane:

~ $ env
ELASTICSEARCH_CLUSTER-NODES=elasticsearch:9200
JAVA_ALPINE_VERSION=8.212.04-r0
HOSTNAME=17eb9e7fec4c
...

Aby wyodrębnić zmienną:

ESHOST=`env | sed -n 's/ELASTICSEARCH_CLUSTER-NODES=\(.*\)/\1/p'`
Guillaume Paramelle
źródło
-1

Uważam, że w przypadku zmiennych bash dozwolone są tylko litery, cyfry i podkreślniki. Dotyczy to wielu języków programowania (wyjątek stanowi javascript).

Zalecam, aby skrypt nie był zależny od tego rodzaju nazw zmiennych.

W rzeczywistości powinieneś spróbować zaprogramować w taki sposób, aby zastąpić nazwy zmiennych innymi nazwami i to nie robi różnicy. Ogólnie nazwy zmiennych powinny opisywać, co zawiera zmienna. To znacznie ułatwia debugowanie; jeśli nie dla ciebie, to dla następnego programisty, który próbuje znaleźć kod.


źródło
-1

Za pomocą tego envpolecenia można ustawiać i wyłączać zmienne środowiskowe za pomocą łączników „-”.

Aby ustawić należy użyć env uruchomić polecenie: env command. Przekazujesz zmienne w ten sposób:

env a-b=c command

Zobacz, jak działa z:

env a-b=c env

lub dla uproszczenia:

env a-b=c env|grep 'a-b'
neves
źródło