Röviden a következőt szeretném megvalósítani:
$ A='foo=$B' #1
$ B=123 #2
$ echo $A #3
foo=123
$
Meg tudom csinálni pl. printf-fel, de szeretném tudni van-e lehetőség arra, hogy #3 változatlan maradjon.
Kicsit hosszabb példa, csak hogy érthetőbb legyen mit szeretnék elérni:
hello.sh:
#!/bin/bash
# DON'T TOUCH THIS!
echo "$HELLO_MESSAGE"
Normál használat:
$ export HELLO_MESSAGE='Hello, World!'
$ hello.sh
Hello, World!
$
Amit én szeretnék látni:
$ export HELLO_MESSAGE='Hello, $WHO!'
$ WHO='HUP' hello.sh
Hello, HUP!
$
- 6344 megtekintés
Hozzászólások
eval "echo $A"
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Ez kétségtelenül működik, de #3-at módosítja.
- A hozzászóláshoz be kell jelentkezni
Lehet, nem értettem meg, mit értesz változatlanságon. Mi a feladat?
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Van egy shell script, amihez nem akarok nyúlni (mivel git által trackelt fájl), ami használ pár környezeti változót. Az egyik egy viszonylag hosszú string, amiben van egy paraméter, amit szeretnék változtatni hogy tudjam futtatni a scriptet egyszerre több példányban. Nyilván bele fogok nyúlni a konkrét változóba, de nem akarom a teljes változót n példányban lemásolni, hanem azt szeretném ami megmaradna mint globális változó, és annak lenne egy paramétere, ami egy másik (nem globális) változóból jönne.
Tehát a fenti példából: A globális, csak egyszer szeretnék neki értéket adni (#1), B-t mindegyik futtatás előtt változtatnám (#2), #3 pedig egy scriptben van amit nem szeretnék megváltoztatni.
- A hozzászóláshoz be kell jelentkezni
Felejtsd el, nem fog menni. Az echo $A parancs (ha nem tudod megváltoztatni) kiírja az A változó értékét (szóközök mentén robbantva, ez most lényegtelen), de nem végez rajta semmiféle értelmezést vagy újabb változó behelyettesítését.
- A hozzászóláshoz be kell jelentkezni
Az echo-tól nem is várom, ellenben a shell (esetünkben bash) ezt megtehetné amikor értelmezi a $A kifejezést.
- A hozzászóláshoz be kell jelentkezni
Erre gondoltam, csak rosszul fogalmaztam. A $ jel egyszeri változókiértékelést jelent, nem rekurzívan újra meg újra amíg el nem tűnik onnan az összes dollárjel.
- A hozzászóláshoz be kell jelentkezni
echo $A-ra azt adja, hogy "foo=$B" a foo=123 helyett lenne az elvárt működés?
- A hozzászóláshoz be kell jelentkezni
Igen. Tisztában vagyok vele, hogy a ' miatt nem működik, de nehéz úgy példát írni egy működő scriptre amire még nem tudom a megoldást. :)
- A hozzászóláshoz be kell jelentkezni
A="foo=$B"
De nem kizárt, hogy félreértettem a problémát.
-----
(&%;_98\<|{3W10Tut,P0/on&Jkj"Fg}|B/!~}|{z(8qv55sr1C/n--k**;gfe$$5a!BB]\.-
- A hozzászóláshoz be kell jelentkezni
Így B-nek A előtt értéket kellene adni:
$ echo $B
$ A="foo=$B"
$ B=123
$ echo $A
foo=
$
- A hozzászóláshoz be kell jelentkezni
$ cat somescript_helper
#!/bin/sh
TMPNAME="somescript.$$"
sed 's/foo/bar/g' somescript >"$TMPNAME"
exec "$TMPNAME"
- A hozzászóláshoz be kell jelentkezni
Amit keresel, ahhoz nagyon hasonló az un. nameref. Ím a példa:
$ unset a b
$ typeset -n a=b
$ echo $a
$ b=3
$ echo $a
3
$ b=4
$ echo $a
4
$
A funkció a ksh93-ban jelent meg először (tudtommal), de átvették a bash-ban is. (bash-ban éppen írhatnád a typedef helyett a declare parancsot is, de akkor kevésbé lenne hordozható) Hogy a feladatodhoz tudod-e használni, azt nem tudom.
- A hozzászóláshoz be kell jelentkezni
Köszönöm, ez lesz az! Jelenleg még nem tudtam kipróbálni mert a gép amin kellene egy CentOS 6.6 bash 4.1.2-vel, a nameref pedig a 4.3-ban jelent meg ha jól látom... Kerítek valahonnan egy újabb bash-t.
- A hozzászóláshoz be kell jelentkezni
Gondolkoztam egy kicsit a dolgon, és nem nagyon látom, hogy ezt az eredeti kód módosítása nélkül hogyan tudnád használni. Ha meg módosítod a ködot, akkor már kevésbé macerás megoldást is használhatsz.
Tegyük fel, kell egy ciklus amit 0-tól "a"-ig akarsz futtatni, de a célod az, hogy hol így, hol úgy fusson. Ekkor az első verzió nyilván valahogy így nézne ki:
$ cat lala.sh
a=4
i=0
while (( i < a )) ; do
echo $i
(( i = i + 1 ))
done
(Nyilván sok mindent lehet másként, most ne arra koncentráljunk.) Ha módosítani akarod a ciklus futását, akkor a kezdő értékadást átírod. Fent emlegtett nameref-fel persze látszólag egyszerűbb, a kezdeti módosítás után sosem kell hozzányúlni a kódhoz (igaz, cserébe a futtatás macerásab lett):
$ cat lala.sh
typeset -n a=b
i=0
while (( i < a )) ; do
echo $i
(( i = i + 1 ))
done
$ env b=3 ksh93 lala.sh
0
1
2
$ env b=5 bash lala.sh
0
1
2
3
4
Igazából ezzel az a baj, hogy ilyen erővel át lehetne írni úgy a kódot, hogy eleve a kívülről jövő "b" környezeti változót kezelje (és ne ilyen nyakatekerten) - sőt akár magát a kezdeti értéket is vehetné kívülről.
a="$b"
(esetleg simán kimarad az inicializálás, és csinálj "a" nevű környezeti változót.)
Vagy csak simán az első paraméterben megkapod "a" értékét, aztán shift-elsz egyet a paramétereken, és minden megy az eredeti módon.
a="$1" ; shift
Ekkor persze a hívást megint változtatni kell (a legeslegelsőhöz képest)
A végeredmény kb ugyanaz, de a nameref egy sokkal kevésbé hordozható (pláne ha tényleg csak 4.3-as bash-ban jelent meg), sokkal kevesebbek által ismert lehetőség. De használatához ugyanúgy kell mindent (a kódot és a futtatást) változtani, mint az előző két módszerhez. Tudtommal a nameref "tulajdonság" nem öröklődik shellek között (persze a Shellshock óta sok mindent el tudok képzelni) - így a módosítást azzal sem úszod meg.
- A hozzászóláshoz be kell jelentkezni
Ha nem örökli, akkor sajnos tényleg nem jó.
Közben végiggondoltam hogy egy egysoros scripttel egész kulturáltan meg lehet valósítani (lásd topicindító hozzászólás):
myhello.sh:
#!/bin/sh
HELLO_MESSAGE="Hello, $WHO" hello.sh
Használat:
$ WHO='HUP' myhello.sh
Hello, HUP!
$
A gond ezzel az, hogy a HELLO_MESSAGE WHO-s alakja csak ebben a scriptben van definiálva, nem egy globális változó ezért a hello.sh-t közvetlenül elindítva nem hat rá a WHO változó továbbra sem. Ezzel épp együtt tudok élni, de nem érzem szép megoldásnak.
- A hozzászóláshoz be kell jelentkezni
Vagy ahogy Zahy írta, vagy így:
$ A='foo=$B'
$ echo $A
foo=$B
$ B=123
$ echo $A
foo=$B
$ eval A="$A"
$ echo $A
foo=123
$
- A hozzászóláshoz be kell jelentkezni
Ezzel az a baj hogy kell egy lépés a script meghívása előtt, amit már abban a shellben kell végrehajtani amiből a script meghívásra kerül. Kb. ugyanezt meg tudom valósítani a printf-fel is, amire eredetileg gondoltam:
$ A='foo=%s'
$ B=123
$ A=$(printf $A $B)
$ echo $A
foo=123
$
- A hozzászóláshoz be kell jelentkezni
Ja értem
- A hozzászóláshoz be kell jelentkezni
Lusta vagyok vegiggondolni, csak egy otlet.
Nem az 'export -f'-et keresed?
- A hozzászóláshoz be kell jelentkezni
Más megoldás nem jöhet szóba?
pl. lehet készíteni egy új scriptet, amely lemásolja a fájlt, majd pl. sed-el kicserélni az adott részt. Az újonnan létrejött fájlokat .gitignore-ba lehet rakni/törölni. (esetleg eval...)
- A hozzászóláshoz be kell jelentkezni
Eddig a következő one-linerre jutottam:
$ A='foo=%s'
$ B=123
$ A=$(printf "$A" "$B") eval 'echo $A'
foo=123
$ echo $A
foo=%s
$
Az eval csak akkor kell, ha a sorban később szerepel a $A, script vagy függvény meghívásakor nem szükséges.
Az eredeti problémámat ebben a formában sajnos még nem oldja meg, mivel csak környezeti változókat és paramétereket tudok beállítani mielőtt a script meghívásra kerül, amibe nem fér bele a $(). Ezt viszont már tényleg könnyen át tudom hidalni egy egyszerű scripttel. Hacsak a printf nem akarná értelmezni az inputban szereplő kapcsolónak kinéző stringeket kapcsolónak... Ha más is belefutna: a
printf -- formatstring params...
működik.
- A hozzászóláshoz be kell jelentkezni
printf -- -x -y -z -v
Legalábbis nálam működik a kb 40 éve bevezetett találmány, hogy az opciók végét egy "--" szöveg jelzi. Ami utánavan, az akkor se opció, ha olyan, mint ha.
- A hozzászóláshoz be kell jelentkezni
A -- megoldást ismertem, csak azt nem tudtam hogy ez egy általános megoldás és még bash builtineken is működik. :)
- A hozzászóláshoz be kell jelentkezni
Lehet, hogy nem értem a problémát teljesen,
De nem az input paramétert keresed?
Hívás: hello.sh "alma"
az shban pedig:
$HELLO_MESSAGE = $1
- A hozzászóláshoz be kell jelentkezni
A HELLO_MESSAGE előtt nem kell a $.
- A hozzászóláshoz be kell jelentkezni
Végül a következő megoldást alkalmaztam (topicindító hozzászólás második példáján levezetve):
Lett egy új környezeti változóm, a HELLO_MESSAGE_TEMPLATE. Már ebből hozom létre a HELLO_MESSAGE-et amiből lesz egy default, így:
export HELLO_MESSAGE_TEMPLATE='Hello, %s!'
export HELLO_MESSAGE=$(printf -- "$HELLO_MESSAGE_TEMPLATE" 'World')
Lett egy új script, ami ha létezik, behelyettesíti a megadott paramétert:
#!/bin/sh
if [ -n "$WHO" ]; then
HELLO_MESSAGE=$(printf -- "$HELLO_MESSAGE_TEMPLATE" "$WHO") hello.sh "$@"
else
hello.sh "$@"
fi
Így a következő módon lehet futtatni az eredeti scriptet:
$ hello.sh # eredeti változat
Hello, World!
$ myhello.sh # saját script, de az eredeti eredményt adva
Hello, World!
$ WHO='HUP' myhello.sh # saját script, paraméteres változóbehelyettesítés
Hello, HUP!
$
Egy kis munkával egész általánosra meg lehetne csinálni, de ehhez most már nincs kedvem.
- A hozzászóláshoz be kell jelentkezni
WORKAROUNDED
- A hozzászóláshoz be kell jelentkezni
szénné égek geci
- A hozzászóláshoz be kell jelentkezni
Beavatnátok engem is mi a gond ezzel?
- A hozzászóláshoz be kell jelentkezni
(A workaround egy probléma megkerülése: főnév. Megkerülve a probléma: worked around. A workarounded olyasmi, mint a felásózott kert, vagy a kikalapácsolt kasztni. VISZONT: sokáig a telnet meg az ftp is csak főnév volt, aztán ki nem szarta le. Szóval sose legyen nagyobb szégyened, max. picit előrébb jársz, mint az angol méjnsztrím.)
- A hozzászóláshoz be kell jelentkezni
mi a baj kikalapácsolt kasztni kifejezéssel?
- A hozzászóláshoz be kell jelentkezni
Kikalapált. Ez a főnévből képzett múltidejű ige eléggé erőltetett szerintem.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Főnevet tettél múltidőbe.
- A hozzászóláshoz be kell jelentkezni
lawyered
grammar nazi'd
googled/binged
smartassed
ssh'd / vpn'd
csak hogy néáhnyat említsek, amiket nem egyszer hallottam már
lépj túl rajta, ezért nem éri meg idegeskedni
- A hozzászóláshoz be kell jelentkezni
Faszluk vagy, de túllépek rajta.
- A hozzászóláshoz be kell jelentkezni
Tényleg, köszi! Így jobb? :)
- A hozzászóláshoz be kell jelentkezni
Múlt időbe.
- A hozzászóláshoz be kell jelentkezni
Szénné égek, geci.
- A hozzászóláshoz be kell jelentkezni