Takže udělat něco takového v bash
a většina ostatních shellů nebude fungovat při vytváření více podadresářů nebo souborů v podadresářích…
mkdir */test
touch */hello.txt
Samozřejmě existuje mnoho způsobů, jak to skutečně udělat, já preferuji použití find
pokud je to možné, místo použití for
smyčka, hlavně kvůli čitelnosti.
Ale moje otázka zní, proč výše uvedené nefunguje?
Z toho, co jsem pochopil, je to proto, že úplný cílový soubor/cesta neexistuje, ale určitě je to dobrá věc, když se snažím mkdir
nebo touch
. Vždy jsem se jen posunul dál a nikdy jsem to nezpochybňoval.
Ale má pro to někdo slušné vysvětlení, které mi pomůže to jednou provždy pochopit?
Přijatá odpověď:
Bod, který vám možná uniká – se kterým má mnoho lidí potíže,
zvláště pokud mají zkušenosti s jinými operačními systémy, než přijdou na *nix
– je to, že v mnoha jiných operačních systémech jsou zástupné znaky na příkazového řádku se normálně předávají příkazu zpracovat, jak uzná za vhodné. Například v příkazovém řádku systému Windows
rename *.jpeg *.jpg
Zatímco v *nix, za účelem zjednodušení práce
programátorů jednotlivých příkazů (např. mv
), zástupné znaky
(pokud nejsou uvozovány nebo escapovány) zpracovává shell
způsobem, který je nezávislý na rozhraní a funkčnosti
příkazu, jehož jsou zástupné znaky argumenty.
Většina programů, které berou názvy souborů jako argumenty příkazového řádku, očekává existenci těchto souborů
(ano, mkdir
a touch
jsou výjimky z tohoto pravidla,
stejně jako mkfifo
, mknod
a v částečné míře cp
, ln
, mv
a rename
;
a pravděpodobně existují další),
, takže ve skutečnosti nemá smysl, aby shell rozšiřoval zástupné znaky
na názvy souborů, které neexistují.
A pro shell (a tím myslím každý shell –
Bourne, bash, csh, fish, ksh, zsh, atd...) zacházet s výjimkami jinak
by byl pravděpodobně příliš velký problém.
To znamená, že existuje několik způsobů, jak dosáhnout výsledku, jaký chcete.
Pokud víte, na co se zástupný znak rozšíří,
a není dlouhý, můžete jej vygenerovat pomocí rozšíření složené závorky:
touch {red,orange,yellow,green,blue,indigo,violet}/rgb.txt
Obecnější řešení:
sh -c 'for arg do mkdir -- "$arg"/test; done' -- *
Gilles mi pomohl najít jiný způsob
, jak to udělat v bash.
benbradley=(*)
mkdir "${benbradley[@]/%//test}"
Zřejmě benbradley
je zde pouze identifikátor; můžete použít libovolné jméno
(např. libovolné písmeno).
Trvalo mi několik pokusů, než jsem to udělal správně, tak mi to dovolte rozebrat:
identifier=value
vytvoří (skalární) proměnnou s názvemidentifier
(pokud již neexistuje) a přiřadí hodnotuvalue
k tomu.
NapříkladG=Man
.
Na skalární proměnnou můžete odkazovat pomocí$identifier
;
například$G
, nebo bezpečněji jako${identifier}
.
Například$Gage
a$Gilla
může být nedefinováno,
ale${G}age
jeManage
a${G}illa
jeManilla
.identifier=(value1 value2 … )
vytvoří proměnnou pole s názvemidentifier
(pokud již neexistuje) a přiřadí mu uvedené hodnoty.
Například
spektrum=(červená oranžová žlutá zelená modrá indigová fialová)
nebo
all_text_files=(*.txt)
$name
bude odkazovat na první prvek (a je tedy docela k ničemu).
Na libovolný prvek můžete odkazovat jako ${name[subscript]}
;
například ${spectrum[0]}
je red
a ${spectrum[4]}
je blue
.
A můžete použít ${name[@]}
a ${name[*]}
odkazovat na celé pole.
Takže tady je to po částech:
" ${ benbradley[@] / % / /test } "
${parameter/pattern/string}
rozšiřuje${parameter}
a nahradí nejdelší shodu
zpattern
sstring
.- Pokud
pattern
začíná#
,
musí se shodovat na začátku rozšířené hodnotyparameter
.
Pokudpattern
začíná%
,
musí se shodovat na konci rozšířené hodnotyparameter
.
Jinými slovy,
chová se jako
(the-rest_of_the_regulex) $
(ano, to se zdá trochu obráceně).
Takže pattern
to je jen %
je jako regulární výraz, který je pouze $
–
odpovídá konci vstupního řetězce (vyhledávací mezera).
- A já používám
string
z/test
.
Takže toto nahradí konec parametru/test
(tj. připojí se/test
na parametr). - Další věc o
${parameter/pattern/string}
to není intuitivní, je to vždy končí}
.
Nemusí a nemůže , končí třetím/
.
Proto/
vstring
nelze interpretovat jako oddělovač,
a proto můžeme mítstring
z/test
aniž byste museli escapovat/
. - Pokud
parameter
je proměnná pole
s indexem@
nebo*
,
operace substituce se postupně aplikuje na každý člen pole. - Když na pole odkazujete jako
${name[@]}
(spíše než${name[*]}
) a výsledky vložte do dvojitých uvozovek,
zachováte integritu prvků pole
(tj. zachováte v nich mezery a další speciální znaky)
aniž byste jednotlivé prvky slučovali do jedno dlouhé slovo.