Pokud do skriptu vložím #!/bin/bash
nahoře to bude fungovat dobře:
cp directory/{foo,bar} destination
U sh se však zobrazí chyba „žádný takový soubor nebo adresář“. Existuje v sh jiný způsob, jak dosáhnout stejného konečného cíle jedním příkazem?
Přijatá odpověď:
Jak jste si všimli, ne všechny skořepiny podporují expanzi vzpěry.
Způsob 1:Dvě samostatné cesty (tj. zapsání předpony dvakrát)
Pokud je vaším cílem opravdu to udělat jedním příkazem, jednoduchý způsob je:
cp directory/file1 directory/file2 destination
cp
příkaz podporuje více zdrojových argumentů následovaných argumentem cíle. Ve skutečnosti se to děje s příkazem, který pro vás funguje v Bash. Bash provede rozšíření složené závorky, které převede příkaz, který jste používali, na příkaz uvedený výše. To znamená, že když spustíte cp directory/{file1,file2} destination
v Bash, cp
příkaz nikdy nevidí žádné složené závorky.
Takový příkaz je jednoduchý a snadno pochopitelný. Navrhuji to zvážit.
Způsob 2:Proměnná pro prefix
Ale pokud je vaším cílem vyhnout se opakování vy, pak to možná raději neuděláte tímto způsobem, zvláště pokud jde o directory
je vlastně dlouhá cesta. Pokud byste totiž museli později ve skriptu upravit cestu, museli byste provést změny v obou výskytech.
Můžete uložit directory
(nebo cokoli, pravděpodobně delší cesta) v proměnné shellu:
dir='directory'
cp "$dir/file1" "$dir/file2" destination
$dir
je rozšíření parametrů. Shell jej nahradí hodnotou uloženou v proměnné dir
. Při použití rozšíření parametrů byste neměli vynechat dvojité uvozovky – kromě výjimečného případu, kdy chcete, aby se provedlo dělení polí a globování. (To platí i pro Bash.)
To jsou dva příkazy, ale pokud je vaším skutečným cílem vyhnout se opakování, může to být to, co chcete. Mohl bys napsat
dir='directory'; cp "$dir/file1" "$dir/file2" destination
aby to bylo „jeden příkaz“, ale není to kratší a je to o něco méně čitelné.
(Všimněte si, že nemůžete jednoduše odstranit ;
tam. Výsledkem by byl dobře vytvořený příkaz, ale nedělal by to, co chcete. Spustilo by to cp
předá proměnnou prostředí nazvanou dir
s hodnotou directory
do cp
prostředí příkazu. Protože je to shell a ne cp
příkaz, který rozšiřuje dir
, to by nefungovalo.)
Způsob 3:cd
ig na předponu
Pokud váš skript po provedení této operace nedělá nic jiného nebo nezáleží na tom, jaký je aktuální adresář pro následující příkazy, pak if destination
je absolutní cesta , můžete použít:
cd directory
cp file1 file2 destination
Ale nedoporučuji to pro skriptování, pokud váš skript neprovádí následné akce, které těží z toho, že jsou spouštěny z tohoto adresáře, nebo pokud je nelze zapsat stručněji nebo jednodušeji, když jsou spouštěny z tohoto adresáře. Kromě případů, kdy je adresář, ze kterého je skript spouštěn, smysluplný Pokud jde o účel scénáře, spoléhání se na něj může ztížit uvažování o scénáři; dále pokud cd
příkaz uspěje, ale cp
příkaz selže, výsledné chybové zprávy mohou být méně než plně svítivé. Místo toho zmiňuji techniku cd
do zdrojového adresáře, protože je to užitečný vzor pro interaktivní použití shellu.
(Jak zdůraznil Hannu, do (
) můžete uzavřít libovolný počet příkazů dohromady )
jejich spouštění v podshellu a změny prostředí prostředí, včetně efektu cd
, nebude po spuštění příkazu přetrvávat. Toto je široce užitečná technika a bylo podstatné opomenutí, že jsem ji nezmínil. Upozorňujeme však, že to nezmírňuje žádné problémy související s relativní cestou pro destination
.)
Všimněte si, že pokud cd
příkaz selže, ostatní příkazy se stále obvykle spustí. Mohlo by to zkopírovat různé soubory, které kopírovat nechcete (pokud jsou v adresáři, ze kterého byl skript spuštěn, další soubory se stejnými názvy) nebo způsobit matoucí chybové zprávy. Můžete tedy preferovat:
cd directory && cp file1 file2 destination
&&
způsobí spuštění druhého příkazu pouze v případě, že první příkaz uspěl. Všimněte si, že to stále nezruší účinek spuštění prvního příkazu. Po spuštění celé věci budete stále v directory
, pokud jste jej nespustili v podshellu s (
)
.