Daugiau
Kaip "Bash" scenarijuje iteruoti argumentus
Turiu sudėtingą komandą, iš kurios norėčiau sukurti shell/bash scenarijų. Ją galiu lengvai užrašyti kaip $1
:
foo $1 args -o $1.ext
Noriu, kad scenarijui būtų galima perduoti kelis įvesties vardus. Kaip teisingai tai padaryti?
Ir, žinoma, noriu tvarkyti failų pavadinimus su tarpais.
830
3
Naudokite
"$@"
visiems argumentams reikšti:Taip bus iteruojamas kiekvienas argumentas ir spausdinamas atskiroje eilutėje. $@ elgiasi kaip $*, išskyrus tai, kad cituojant argumentai tinkamai suskaidomi, jei juose yra tarpų:
Perrašytas dabar jau ištrintas atsakymas pagal VonC. Robert Gamble's glaustame atsakyme tiesiogiai nagrinėjamas klausimas. Šiame atsakyme plačiau aptariami kai kurie klausimai, susiję su failų pavadinimais, kuriuose yra tarpų. Taip pat žr: ${1:+"$@"} in /bin/sh Pagrindinė tezė:
"$@"
yra teisinga, o$*
(be kabučių) beveik visada klaidinga. Taip yra todėl, kad"$@"
veikia gerai, kai argumentuose yra tarpai, o veikia taip pat, kaip$*
, kai jų nėra. Tam tikromis aplinkybėmis"$*"
taip pat tinka, bet"$@"
paprastai (bet ne visada) veikia tose pačiose vietose. Neįrašyti$@
ir$*
yra lygiaverčiai (ir beveik visada neteisingi). Taigi, kuo skiriasi$*
,$@
,"$*"
ir"$@"
? Visi jie susiję su 'visais apvalkalo argumentais', tačiau atlieka skirtingus veiksmus. Kai$*
ir$@
nėra cituojami, jie atlieka tą patį. Jie kiekvieną 'žodį' (ne baltųjų ženklų seką) traktuoja kaip atskirą argumentą. Tačiau cituojamos formos yra visiškai skirtingos:"$*"
traktuoja argumentų sąrašą kaip vieną tarpeliais atskirtą eilutę, o"$@"
traktuoja argumentus beveik taip pat, kaip jie buvo nurodyti komandinėje eilutėje."$@"
išsiplečia į nieką, kai nėra pozicionuojamųjų argumentų;"$*"
išsiplečia į tuščią eilutę — ir taip, yra skirtumas, nors jį gali būti sunku pastebėti. Daugiau informacijos rasite toliau, po (nestandartinės) komandosal
įvedimo. Antroji tezė: jei reikia apdoroti argumentus su tarpais ir tada juos perduoti kitoms komandoms, tuomet kartais reikia nestandartinių pagalbos priemonių. (Arba atsargiai naudokite masyvus:"${Masyvas[@]}"
elgiasi analogiškai kaip"$@"
.) Pavyzdys:Kodėl tai neveikia? Neveikia, nes apvalkalas apdoroja kabutes prieš jas išplėsdamas kintamuosius. Taigi, kad apvalkalas atkreiptų dėmesį į kabutes, įterptas į
$var
, turite naudotieval
:Tai tampa labai sudėtinga, kai turite tokius failų pavadinimus kaip "
Jis sakė, "Nedarykite to!"
" (su kabutėmis, dvigubomis kabutėmis ir tarpais).Kriauklės (visos) ne itin palengvina tokių todėl (kaip bebūtų keista) daugelis "Unix" programų nelabai gerai atlieka šį darbą. juos apdoroti. "Unix" sistemoje failo pavadinime (viename komponente) gali būti bet kokie simboliai, išskyrus pasvirąjį brūkšnį ir NUL
'\0'
. Tačiau apvalkalai primygtinai rekomenduoja nenaudoti tarpų, naujų eilučių ar skirtukų niekur kelio pavadinime. Dėl to ir standartiniuose Unix failų varduose nėra tarpų ir pan. Kai susiduriama su failų vardais, kuriuose gali būti tarpų ir kt. simbolių, turite būti labai atsargūs, ir aš pastebėjau, kad seniai, kad man prireikė programos, kuri nėra standartinė "Unix" sistemoje. Pavadinau jąescape
(1.1 versijos data - 1989-08-23T16:01:45Z). Štaiescape
naudojimo pavyzdys - su SCCS valdymo sistema. Tai yra viršelio scenarijus, kuris atlieka irdelta
(pagalvokite check-in), irGet
(pagalvokite check-out). Įvairūs argumentai, ypač-y
(priežastis, dėl kurios atlikote pakeitimą) yra tuščių ir naujų eilučių. Atkreipkite dėmesį, kad scenarijus sukurtas 1992 m., todėl jame naudojamos atgalinės žymės, o ne$(cmd ...)
ir pirmoje eilutėje nenaudoja#!/bin/sh
.(Tikriausiai šiais laikais taip kruopščiai nenaudočiau escape - tai yra pavyzdžiui, nereikia su
-e
argumentu, bet apskritai tai yra vienas iš mano paprastesnių skriptų, naudojančiųescape
.) Programaescape
tiesiog išveda savo argumentus, panašiai kaipecho
tačiau ji užtikrina, kad argumentai būtų apsaugoti, kad juos būtų galima naudoti sueval
(vienas iševal
lygių; turiu programą, kuri atliko nuotolinį shell vykdymą, ir jai reikėjo apsaugotiescape
išvestį).Turiu kitą programą, pavadintą
al
, kurios argumentai išvardijami po vieną eilutėje (ir ji dar senesnė: 1987-01-27T14:35:49 versija 1.1). Ji naudingiausia derinant scenarijus, nes ją galima prijungti prie į komandų eilutę, kad pamatytumėte, kokie argumentai iš tikrųjų perduodami komandai.[Pridėta: O dabar, norėdami parodyti skirtumą tarp įvairių
"$@"
užrašų, pateikiame dar vieną pavyzdį:Atkreipkite dėmesį, kad niekas neišsaugo originalių tuščių vietų tarp
*
ir*/*
komandinėje eilutėje. Taip pat atkreipkite dėmesį, kad galite pakeisti 'komandinės eilutės argumentus' apvalkale naudodami:Taip nustatomos 4 parinktys: '
naujas
', 'opt
', 'ir
' ir 'arg su tarpais
'.] Hmm, tai'gana ilgas atsakymas - gal geriau tinka terminas egzegezė. Pirminį
escape
kodą galima gauti paprašius (el. paštu firstname dot lastname at gmail dot com).al
šaltinio kodas yra neįtikėtinai paprastas:Štai ir viskas. Tai yra lygiavertis
test.sh
scenarijus, kurį parodė Robertas Gamble'as, ir galėtų būti parašytas kaip apvalkalo funkcija (tačiau apvalkalo funkcijos neegzistavo vietinėje Bourne'o apvalkalo versijoje, kai pirmą kartą parašiaual
). Taip pat atkreipkite dėmesį, kadal
galite parašyti kaip paprastą apvalkalo scenarijų:Sąlyga reikalinga tam, kad jis nesukurtų išvesties, kai jam neperduodami jokie argumentai. Komanda
printf
išves tuščią eilutę tik su formato eilutės argumentu, tačiau C programa nieko neišves.Atkreipkite dėmesį, kad Roberto atsakymas yra teisingas, jis veikia ir
sh
. Galite jį dar labiau supaprastinti:yra lygiavertis:
T.y., jums nieko nereikia!
Testavimas (
$
yra komandų eilutė):Pirmą kartą apie tai perskaičiau Kernighan ir Pike knygoje Unix programavimo aplinka.
bash
,help for
tai dokumentuoja:... ;] do COMMANDS; done`