Sziasztok,
Gondoltam indítok egy témát - ismerkedem a bash sel. Észrevettem egy jelenséget, ami párszor megnehezítette a dolgomat.Itt van pl ez a sor:
find -name "*.${i}" -type f -exec mv --target-directory=${i} {} \;
Ennél muszáj {} jelek közé tenni az i változót,mert különben nem működik.
De vannak olyan helyzetek, amikor elegendő a () jelek is:
echo "$(i)és itt folytatódik a szöveg"
Utánanéztem a google-m és ezt variable mangling nek nevezik angolul, elvileg. A Büki András Héjprogramozás címe is említi rögtön az elején, a 7. oldalon. Az első esetben a probléma abból adódik szerintem, hogy maga a find program úgy lett leprogramozva, hogy a -name kapcsolót követően "" jelek közé kell tenni, azt amit keresünk, de ha változó az, akkor kellenek a {} jelek köré.
Van még ehhez hasonló nyalánkság ebben a témában, amiről már tudtok, mert beleakadtatok a mindennapok során? Vagy itt vége ennek a történetnek?
Ha valami olyan bődületes és egy hozzáértő számára triviális dolgot hoztam fel, akkor Tőlük elnézést kérek.
- 8334 megtekintés
Hozzászólások
"De vannak olyan helyzetek, amikor elegendő a () jelek is:
echo "$(i)és itt folytatódik a szöveg""
A $() az a command substitution egyik formája, ezért a shell azt az "i"-t nem mint változónevet fogja kezelni, hanem mint végrehajtandó parancsot.
- A hozzászóláshoz be kell jelentkezni
Akkor $(valami) == `valami` - vel?
-- Zoli
- A hozzászóláshoz be kell jelentkezni
Végülis igen, $()-nek annyi előnye van, hogy egyszerűen egymásba ágyazható.
- A hozzászóláshoz be kell jelentkezni
Bash alatt irtó fontos tudni, hogy pontosan mit adsz meg paraméterül, illetve ha tudod, hogy mit szeretnél, akkor azt hogy kell elérni
http://wiki.bash-hackers.org/syntax/quoting
http://www.gnu.org/software/bash/manual/bashref.html
- A hozzászóláshoz be kell jelentkezni
Elolvasom a linkeket. Abban tudnál segíteni, hogy mit jelent az, hogy:
"parancssori paraméterek száma"
Elkezd a könyv beszélni erről, de nem magyarázza meg, hogy mit jelent. Van valami köze a 0. argumentumhoz? Erről tudom, hogy maga a programnak a neve. Pl. ha azt írom be, hogy ls -l, akkor az ls a 0. paraméter, az l pedig az első, ugye?
-- Zoli
- A hozzászóláshoz be kell jelentkezni
igen, de ezeket tudod tesztelni úgy, hogy pl. ennek a szkriptnek adsz meg paramétereket:
#!/bin/bash
echo Arg count: $#
echo Args: $*
n=0
while [ $# -gt 0 ]
do
let n++
echo Arg$n: \'$1\'
shift
done
- A hozzászóláshoz be kell jelentkezni
köszi, ezt nem igazán értem, hogyan tudok tesztelni ezzel.
-- Zoli
- A hozzászóláshoz be kell jelentkezni
Ez a script kiírogatja a neki átadott paramétereket külön sorokba. Így jobban látszik, hogy paraméter átadásnál szeparál az egy vagy több szóköz, a neline, a tabulátor, ugyanakkor idézőjelek, aposztrofok egyben tartják a stringet, de literális lesz a szóköz akkor is, ha backslash-sel escape-eled.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Újabb érdekesség:
sh nevű könyvtárat nem tud csak úgy símán eltávolítani, mert parancsnak veszi:
rmdir sh
-- Zoli
- A hozzászóláshoz be kell jelentkezni
Ott valamit elállíthattál.
Esetleg van egy sh nevű aliasod vagy valami ilyesmire tippelek (nincs kéznél linux, amin megnézhetném).
Normálisan nem lenne szabad parancsként megtalálnia, pláne, ha létező könyvtárat akarsz törölni.
Ha nem létezik, akkor valószínűleg beállítottad, hogy a PATH változóban tárolt könyvtárakat nézze végig a nem létező fájlok megtalálásához. (most nem jut eszembe, hogy ehhez mit is kell tenni :( )
- A hozzászóláshoz be kell jelentkezni
Az alias magára a parancsnévre lenne érvényes (rmdir), csakúgy, mint a PATH.
- A hozzászóláshoz be kell jelentkezni
Lehet, hogy a CDPATH-ra emlékeztem. Legalábbis a man bash nem segített, pedig egyre olyan emlékeim vannak, hogy a bash tud(ott?) path jellegű változót használni fájlokhoz. :(
Az alias csak egy hasraütéses tipp vótt. :)
- A hozzászóláshoz be kell jelentkezni
nincsen alias,
Érdekes, hogy terminalban simán kitörli az sh nevű könyvtárat, de ha scriptbe írom, akkor nem ( geany vel szoktam)
-- Zoli
- A hozzászóláshoz be kell jelentkezni
Mi a hibaüzenet?
- A hozzászóláshoz be kell jelentkezni
Tárgytalan, most működik.
Fogalmam sincsen, hogy egy fél órája miért nem ment.
-- Zoli
- A hozzászóláshoz be kell jelentkezni
az létezhetetlen!
hacsak nem állítottál valamit nagyon el, ahogy elõttem ís írták.
esetleg az IFS változót? vagy a rmdir-t definiáltad fölül?
type rmdir
echo -n "$IFS" | hd
ezeknek a kimenetével kideríthetõ, miért e helytelen mũködés - ha valóban fennáll, amit írsz s nem csak az érzékeid csaltak meg :)
~~~~~~~~
Linux 3.2.0-0.bpo.4-486
Debian 6.0.7
- A hozzászóláshoz be kell jelentkezni
a find program úgy lett leprogramozva, hogy a -name kapcsolót követően "" jelek közé kell tenni, azt amit keresünk, de ha változó [...]
téves, ilyenrõl szó sincs.
a find nem tudja, hogy amikor beírod parancssorba, melyik paraméterét adtad meg literálisan, mleyiket shell változó segítségével, esetleg backtick substitutionnel, stb.
a shell feloldja a magic karaktereket és kifejezéseket ($változó, `backtick`, zárójel, redirection, pipe, escape, stb) és kiforkolja, amit akar(sz) semmi közvetlen információról, arról milyen alakban kapta a program indítására sarkalló parancsot.
a curly bracket használatának a változók szintaktikájában az a létjoga, hogy az ilyen kifejezések egyértelmũek legyenek:
gyum=eper
echo "étel: ${gyum}torta"
tehát, amikor a változó nevét nem követi szóelválasztó jel (pl pont, kötõjel, szóköz), akkor tudassuk a shellel, meddig tart a változó neve.
kezdõ bashinisztáknak javallott bekapcsolni a set -u módot, ami megállítja a script futását, ha inicializálatlan változót kéne feloldania.
(amit sztem elég esetlenül kötetlen változónak magyarítottak)
~~~~~~~~
Linux 3.2.0-0.bpo.4-486
Debian 6.0.7
- A hozzászóláshoz be kell jelentkezni
Kötetlen változó???? Az miért nem jó, hogy "nem létező"?
- A hozzászóláshoz be kell jelentkezni
a nemlétezõ kissé félrevezetõ, mert a bash autovivifikáló nyelv, tehát mielõtt kiértékeli, létrehozza.
én inicializálatlannak fordítanám, vagy legfeljebb maghatározatlannak.
~~~~~~~~
Linux 3.2.0-0.bpo.4-486
Debian 6.0.7
- A hozzászóláshoz be kell jelentkezni
WTF?
unset a
echo ${a-lo}
echo ${a-lo}
Ha igazad lenne, akkor az elso esetben lo, a masodik esetben viszont mar semmi lenne a kiirt szoveg. Idezek ugyanis a manualbol:
"${parameter:-word}
Use Default Values. If parameter is unset or null, the expansion of word is substituted; otherwise, the value of parameter is substituted. ...
In the parameter expansions shown previously, use of the colon in the format results in a test for a parameter that is unset or null; omission of the colon results in a test for a parameter that is only unset."
Szoval en ugy gondolom maradjunk annyban, hogy nem letezo.
- A hozzászóláshoz be kell jelentkezni
a manual nem mond ellent annak amit én mondok.
${variable-default} esetén nem a variable-t oldja fel (az elõzõ hosszászólásomban helyesebb lenne az, hogy "mielõtt feloldaná"), hanem a zárójelezett kifejezést.
valóban nevezhetjük nem létezõnek az unset változót. csak annyit mondtam, hogy félrevezetõ, mert autovivifikál.
hm, elismerem, hogy csak úgy tunik, hogy autovivifikál. az unset változókat nem létrehozza, csak üres sztringre oldja fel õket (persze +u módban).
~~~~~~~~
Linux 3.2.0-0.bpo.4-486
Debian 6.0.7
- A hozzászóláshoz be kell jelentkezni
Előre éreztem, hogy a zárójelezésbe fogsz belekötni.
bash$ unset a
bash$ set | grep '^a=' # nincs kimenet, mert *nincs* "a" nevű változó
bash$ echo $a
bash$ set | grep '^a=' # még most sincs
bash$ echo $a
bash$ set | grep '^a=' # és még most sincs, ez mehet a végtelenségig
Azaz ha a változó nem létezik, csak attól, hogy hivatkozok rá, nem is lesz. Én ezt mondtam.
Az meg a definíció, hogy ha nem-létező változó értékéről bszélünk (+u üzemmódban), az a semmivel egyenlő. De hogy kényelmesebb(*) legyen :-), nem mindegy, hogy ez a semmi "idézőjelek" között van, vagy nem.
bash$ unset a
bash$ b=1
bash$ echo $b $a $b
1 1
bash$ echo "$b" "$a" "$b"
1 1
bash$ # ugye látszik, hogy a második esetben 2 db. szóköz van a 2 db. egyes között?
Szóval GOTO 1: miért is nem hívjuk a nem-létező változót nem-létező változónak? Főleg, hogy a set -u paranccsal, vagy az általam a korábbiakban emlegetett ${változó:-érték} és ${változó-érték} forma segítségével ha kell, meg is tudom különböztetni a "nem-létezőt" a "létezik-de-üres-sztring-az-értéke" félétől? (Azt amúgy elismerem, hogy nehéz, és általában lényegtelen megkülönböztetni az unset a, és az a="" eredményét, pl. a fenti példában sem látszik a különbség.)
(*) persze ettől pont kényelmetlenebb is tud lenni egyes esetekben.
Ui: ja, és az én bash-omban nem kötetlen változó, hanem "felszabadított változó" a hibaüzenet szerint. Ami baromság.
- A hozzászóláshoz be kell jelentkezni
Ja, és hogy miért nem tetszenek az eddig felmerülő magyarítások az unset-re. Vegyük a C programozási nyelvet. Nem túl elterjedt, de van annak interpretált futtatókörnyezete.
main()
{
int X;
int Y = 1;
printf( "%d\n", X );
printf( "%d\n", Y );
printf( "%d\n", Z );
}
Fenti példácskában X létező, de inicializálatlan. Y létező és inicializált, ellenben Z nem létező változó. Azaz X helyén valami memóriaszemét kéne megjelenjen, Y helyett egy egyes, Z-nél pedig az interpreternek kiabálnia, hogy nincs ilyen változó. Azért ez marhára nem mindegy. És ugyanez a heyzet a bash-nál is, csak éppen ott az interpretált futtatókörnyezet a jellemző, meg nem memóriaszemét lesz X helyén, hanem definit üres sztring, és alapvetően nem anyázik Z helyén.
Azaz GOTO 1: nem kötetlen, nem inicializálatlan, nem Zed-agyában-a-fekete-lyuk, hanem nem-létező változó.
De nyitott vagyok az észérvekre. (Amíg meg nem győztök, én nem-létezőként fogom tanítani.)
- A hozzászóláshoz be kell jelentkezni
Amikor közvetlenül kezelünk asszociatív tömböt, fel sem merül annak összekeverése, hogy egy elem nem létezik, vagy csak inicializálalan.
Furcsa, hogy ha a konténer jellege el van dugva, auto beindul a pongyolaság.
- A hozzászóláshoz be kell jelentkezni
Asszociatív tömb használata inkább AWK-ban jellemző. mint shell-scriptben (*). Egyébként remlik, hogy mintha az AWK tényleg úgy működne, hogy a változó (jobbértékként történő) első hivatkozása létre is hozná inicializálatlanként (de meggyőződve nem vagyok róla, sőt a shellel ellentétben azt se tudom hogyan lehetne tesztelni - erre várok tippeket.)
(*) Lefordítom: nem tudok róla, hogy láttam volna élő embert, aki bash-ban asszociatív tömböt használ tudatosan (értsd, nem a néhány beépítve létező változón kívül; mellesleg olyat se, aki ezeket a beépített változókat használta). Igaz, én kevés olyan embert ismerek, aki *tud* sh-ban (pláne bash-ban) programozni. A többség megrémül egy 20 sort, vagy 3-nál több parancsból álló pipe-ot tartalmazó scripttől.
- A hozzászóláshoz be kell jelentkezni
Nem megrémül, csak hatékonyabb(?) eszközt keres. ;)
- A hozzászóláshoz be kell jelentkezni
Előfordul mindkettő.
Azt pl. amikor az sh megkerülésére kiszemelt nyelvben a funkcióhoz szükséges modul és annak függőségeinek összeszedése több időt elvisz, mint leírni azt a 20 sort + esetleg belepislantani a manuálba, hogy minden emlék helyes-e, nem tartom racionálisnak, ha nem folyamatos loadot adó kódot legyártásáról van szó.
- A hozzászóláshoz be kell jelentkezni
Szia,
Csak ellen és elrettentő példának jelentkezem :)
Használtam már bashben asszociatív tömböt, mivel egy modem vezérlő script köteget kellett írnom, és az elején (oh, naív tudatlanság :) ) még azt hittem, a /dev/ttyUSB0-t könnyebb írni, mint C/C++-ból portot nyitni. A végére persze mindkettőt megtanultam, de addigra meg túlságosan előrehaladott a "termék", ahhoz, hogy vissza fordulhassak... (+ a belső kísérleti tool hirtelen már megrendelőnek is lett hirdetve... Aminek nagyon-nagyon örültem...)
Viszont, annyi haszna volt az egésznek, hogy elég alaposan sikerült meg ismerkednem a bashel, és a határaival... És, azt kell mondanom, hogy ha nem is a leggyorsabb, legkézenfekvőbb, de azért nagyon hatékony eszköz tud lenni :)
Üdv,
LuiseX
- A hozzászóláshoz be kell jelentkezni
Csak még egy modellt kerestem az elméletibe forduló csevegés tárgyához, hogy (talán) világosabb legyen, hogy ami nincs, az tényleg nincs.
Ami nekünk kifelé nem asszoc tömb a shellben, az befelé definíció szerint az: minden definiált névhez (itt: változóhoz) 1 érték tartozik, csak a megvalósítás a kérdés. Analóg a legtöbb tisztességes nyelvben (pontosan, az AWK nem sorolható ide) megvalósított hash/map/dictionary/ahogyépphívják viselkedésével, amikor a NEM LÉTEZŐ indexre (ami shellben a változónévnek felel) hivatkozva is kapunk egy alapértelmezett valamit, ami "", undef, null, akármi.
- o -
Ahogy írod, az AWK megalkotásakor úgy gondolták, hogy a tömb nem létező elemére hivatkozásakor az elemet létre kéne hozni. A konkatenáció operátortalansága után ezt tartom az 1. számú nyelvi bakinak.
A jelenség kimutatására ugyanaz az "in" operátor szolgál, amit a minap is felhasználtunk, és amit valószínűleg éppen azért tettek képessé a loopon kívüli működésre, mert anélkül nem lehetnénk biztonságban:
$ awk 'BEGIN { print ("auto" in a) ? " van" : " nincs"; a["auto"] ; print ("auto" in a) ? " van" : " nincs" }'
nincs
van
Látszik, hogy értéket nem adtam az "auto" indexű elemnek, csak gondoltam rá, és az mégis megszületett.
A fícsör csapdája:
awk 'BEGIN { print ("auto" in a) ? " van" : " nincs"; if (a["auto"]) { FELREVEZETO=1} ; print ("auto" in a) ? " van" : " nincs" }'
nincs
van
Az ember akár az "auto" index létezését szeretné ezzel (rosszul) tesztelni, akár az értéket, mellékhatásként rögtön le is gyártja.
Tehát a tiszta út:
awk 'BEGIN { print ("auto" in a) ? " van" : " nincs" ; print ("auto" in a) ? " van" : " nincs"}'
nincs
nincs
Önlektorálás: tkp. az "in" loopban használatával is tesztelhető volna a létezés, csak időrabló volna:
for (i in a) { if (i == "keresett_index") {megvan=1; break} }
- A hozzászóláshoz be kell jelentkezni
A szóköz nem semmi, az valami. Mindamellett engem is zavar, a kódot nem igazán teszi olvashatóvá, hogy szóköz a string konkatenáció. Éppen a bash az, ahol semmi az összefűzés, egész egyszerűen a helyettesítés következménye, hogy amit leírunk valahova, az ott lesz. Szerintem ez utóbbi, a valóban semmi operátor jobban áttekinthető, mint a szóköz operátor.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Szó sincs szóközről.
awk 'BEGIN { a="nincs"; b="space"; print a"itt"b}'
nincsittspace
Egyébként nem csak mi gondoljuk, hogy lehetett volna máshogy:
"It seemed like a good idea at the time."
Brian Kernighan
http://www.gnu.org/software/gawk/manual/html_node/Concatenation.html
- A hozzászóláshoz be kell jelentkezni
Igazad van. Mentségemre szóljon, ezért hittem a szóközben:
space String concatenation.
Gyanítom, azért írtak szóközt, mert ha azt írják, semmi a konkatenálás, akkor egyből felvetődik, hogyan fűzünk össze két változóból stringet. Szóközzel szeparálva ez a kérdés is megoldódik, s magyarázni sem kell a manualban.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
+1
teljesen jogos
--
A legértékesebb idő a pillanat amelyben élsz.
http://phoenix-art.hanzo.hu/
https://sites.google.com/site/jupiter2005ster/
- A hozzászóláshoz be kell jelentkezni
"kezdõ bashinisztáknak javallott bekapcsolni a set -u módot"
Sőt, a set -x-et is, hogy szokják, mennyi mindent művel a beírtakkal az interpreter, mielőtt nekilát a futtatásnak.
Bár minden magára valamit adó dok ezzel kezdi az érdemi részt, erős a hajlam annak a pár mondatnak a meg nem emésztésére.
- A hozzászóláshoz be kell jelentkezni
De akár futtathatod a script-ed így is: "bash -x scriptem"
--
Debian Linux rulez... :D
- A hozzászóláshoz be kell jelentkezni
Megjegyzés: a 'sh' nevű fájl kezelése szerintem nem problémás, inkább ezeket javaslom kezdőknek kipróbálásra (tehát nem éles használatra!) mint fájlneveket: ?test1 *test2 ~test3 $test4 -test5 stb (no meg persze a szóközt tartalmazó neveket)
pl: ls -test5 helyett ls -- -test5 a nyerő, touch *test2 helyett touch '*test2'
- A hozzászóláshoz be kell jelentkezni
és 0x0A-t tartalmazó fájlneveket!
a kötõjel kezdetũ fájlnevekre bevált megoldás még így hivatkozni: ./-test5
engem legtöbbször a ~ feloldásával szivat meg a shell.
illetve érdekes, noha a : nem magic karater, a bash auto completion-je kieszképeli.
~~~~~~~~
Linux 3.2.0-0.bpo.4-486
Debian 6.0.7
- A hozzászóláshoz be kell jelentkezni
No igen... másik kedvencem volt a space-nek látszó 0xff a nevekben. :)
- A hozzászóláshoz be kell jelentkezni
A kettőspont tényleg nem nagy varázsló, de mégis csak az a szeparátor a *PATH változók értékében. Másrészt kifejezetten kedves gesztus, ha rsync/scp használatakor a shell besegít annak tisztázásába, hogy hoszt vagy fájlnév.
- A hozzászóláshoz be kell jelentkezni
besegít?
szerintem egy
scp host:./jokai\:aranyember.pdf .
parancssort így hajt végre:
execve("scp", "host:./jokai:aranyember.pdf", ".");
mert nincs mit kieszképelni a :-on.
utána az scp dolgozza fel hogy az 1. arg mit jelent neki.
ennek csak megtévesztõ hatása van (rámnézve az volt, amíg mögé nem láttam a dolgoknak). azt hiheti a user, hogy már a shell is tudja, hogy egy :-ot tartalmazó stringben az 1. tag egy hoszt név, a 2. a path és ha "host:./jokai:aranyember.pdf"-et írna, akkor nem lenne egyértelmũ, hogy "host" vagy "host:./jokai" a hosztnév.
ezt a hatást erõsíti sok terjesztésben a completion függvény foglalkozik vele, hogy az rsync/scp argumentumában van-e hosztnév (*), de ez nem beépített képessége a shellnek, úgy mint a wildcardok feloldása. ezért eshet orcára az ember, amikor nem oldja fel a shell neki az
scp host:./*.pdf .
parancsban a *-ot.
(*)
ennek külön tudok örülni, mert reflexbõl nyomogatom a TAB-ot és távoli, lassú elérésũ gépekrõl való scp-zésnél mindig megtorpan az élet, amíg a completion fgv a háttérben bemászik a gépre és fájllistát kér.
~~~~~~~~
Linux 3.2.0-0.bpo.4-486
Debian 6.0.7
- A hozzászóláshoz be kell jelentkezni
Olyan nemrég történt - és én teljesen kezdő vagyok bash ből, meg minden programozási nyelvből -, hogy gondot okoztak a szóközt tartalmazó fájlnevek. Ha jól emlékszem for ciklusban, én azt akkor úgy oldottam meg, hogy előtte kicseréltem az összes fájlban a szóközöket _ ra, és máris jó lett:-)
Amiket írkáltok az nekem most magas:-)
-- Zoli
- A hozzászóláshoz be kell jelentkezni
És mit csinálsz, ha _ is van a filenévben?
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Lecserélem először valami másra pl . ra, aztán a pontot _ ra:-)
-- Zoli
- A hozzászóláshoz be kell jelentkezni
És ha pont is van a filenévben? Arra céloztam, hogy óvatosan a cserékkel, mert lehet, visszafelé már nem tudod megcsinálni. Lehetne például hasonló technikát alkalmazni, mint amit a shell csinál: escape-elni. Ezzel az a baj, hogy nő a filenév hossza, az meg baj, mert többnyire 255 byte lehet.
Tehát csináld jól! Az egyik lehetőség, hogy idézőjelek között használod fel a filenevet, a másik, hogy módosítod az IFS értékét.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
nomeg ha ro az fs...
~~~~~~~~
Linux 3.2.0-0.bpo.4-486
Debian 6.0.7
- A hozzászóláshoz be kell jelentkezni
Valóban...
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Egy jó gyűjtemény a bash-ban elkövethető hibákról:
- A hozzászóláshoz be kell jelentkezni