-exec opciójának megértése, hogy folyamatosan a
find . -name "FILENAME" -exec rm {} \;
főleg azért, mert nem látom, hogy pontosan hogyan működik a -exec
rész. Mit jelentenek a zárójelek, a hátsó perjel és a pontosvessző? Vannak más felhasználási esetek is ez a szintaxis?
Megjegyzések
Válasz
Ez a válasz a következő részekben érkezik:
- A
-exec
-
-exec
használata ash -c
-
-exec ... {} +
- használata
-execdir
alapértelmezett használata
A -exec
alapértelmezett használata
A -exec
opció egy külső segédprogramot igényel, opcionális argumentumokkal, az argumentuma és végrehajtja.
Ha a {}
karakterlánc bárhol megtalálható az adott parancsban, akkor annak minden példányát felváltja a jelenleg feldolgozott elérési út ( pl. ./some/path/FILENAME
). A legtöbb héjban a két karaktert {}
nem kell idézni.
A parancs le kell állítani egy ;
felirattal a find
számára, hogy megtudja, hol ér véget (mivel később lehetnek további lehetőségek) s). A ;
héj elleni védelme érdekében \;
vagy ";"
, különben a héj a find
parancs végének fogja látni.
Példa (a \
a az első két sor vége csak a folytatásra vonatkozik):
find . -type f -name "*.txt" \ -exec grep -q "hello" {} ";" \ -exec cat {} ";"
Ez megtalálja az összes szokásos fájlt (-type f
), amelynek nevei megegyeznek az *.txt
mintával az aktuális könyvtárban vagy alatt. Ezután tesztelni fogja, hogy a hello
karakterlánc előfordul-e valamelyik megtalált fájlban a grep -q
használatával (amely nem hoz létre kimenetet, csak kilépést) állapot). Azon fájlok esetében, amelyek tartalmazzák a karakterláncot, a cat
parancs végrehajtásra kerül, hogy a fájl tartalmát a terminálhoz adja ki.
Mindegyik -exec
úgy is viselkedik, mint egy “teszt” a find
által talált útvonalakon, akárcsak -type
és -name
igen. Ha a parancs nulla kilépési állapotot ad vissza (ami “sikert” jelent), akkor a find
parancs következő részét vesszük figyelembe, különben a find
parancs folytatódik a következő útvonalnévvel. Ezt használja a fenti példa a hello
karakterláncot tartalmazó fájlok megkeresésére, de az összes többi fájl figyelmen kívül hagyására.
A fenti példa a két leggyakoribb használatot szemlélteti. -exec
esetek:
- Tesztként a keresés további korlátozására.
- Valamilyen művelet végrehajtása a megtaláltakon útvonalnév (általában, de nem feltétlenül a
find
parancs végén).
a sh -c
kombinációval, amelyet -exec
képes végrehajtani, egy külső segédprogramra korlátozódik opcionális argumentumokkal.A shell beépítettek, függvények, feltételek, csővezetékek, átirányítások stb. Közvetlen használata a -exec
szolgáltatással csak akkor lehetséges, ha egy sh -c
gyermekhéj.
Ha bash
funkciókra van szükség, akkor a iv id = helyett használja a bash -c
parancsot. “73af3270ae”>
.
sh -c
futtatja a /bin/sh
parancsfájlot a parancssorban, opcionális parancssori argumentumok követik az adott szkriptet.
Egyszerű példa a sh -c
használatára önmagában, find
nélkül :
sh -c "echo "You gave me $1, thanks!"" sh "apples"
Ez két argumentumot ad át a gyermek shell parancsfájlnak. Ezeket a $0
és $1
mappákba helyezzük a szkript használatához.
-
A string
sh
. Ez$0
néven lesz elérhető a parancsfájl belsejében, és ha a belső héj hibaüzenetet küld, akkor ezt a karakterláncot fogja előtagolni. -
A
apples
argumentum$1
néven érhető el a szkriptben, és ha több argumentum lett volna, akkor ezek elérhetőek lettek volna$2
,$3
stb. Ezek elérhetők lennének a"$@"
listában is (kivéve:$0
, amely nem lenne a"$@"
része).
Ez hasznos -exec
-vel kombinálva, mivel ez lehetővé teszi számunkra, hogy önkényesen összetett szkripteket készítsünk, amelyek a find
által megtalált útnevekre hatnak.
Példa: Keresse meg az összes szokásos fájlt, amely rendelkezik bizonyos fájlnév utótaggal, és módosítsa ezt a fájlnév utótagot valamilyen más utótagra, ahol az utótagokat változókban tartják:
from=text # Find files that have names like something.text to=txt # Change the .text suffix to .txt find . -type f -name "*.$from" -exec sh -c "mv "$3" "${3%.$1}.$2"" sh "$from" "$to" {} ";"
Inte belsejében rnal szkript, $1
lenne a karakterlánc text
, a $2
karakterlánc a txt
és a $3
bármi is lenne, amelyet find
megtalált nekünk. A (z) ${3%.$1}
kiterjesztés paraméter az útvonalnevet veszi fel, és eltávolítja belőle a .text
utótagot.
Vagy a dirname
/ basename
:
find . -type f -name "*.$from" -exec sh -c " mv "$3" "$(dirname "$3")/$(basename "$3" ".$1").$2"" sh "$from" "$to" {} ";"
vagy hozzáadott változókkal a belső szkript:
find . -type f -name "*.$from" -exec sh -c " from=$1; to=$2; pathname=$3 mv "$pathname" "$(dirname "$pathname")/$(basename "$pathname" ".$from").$to"" sh "$from" "$to" {} ";"
Vegye figyelembe, hogy ebben az utolsó változatban a from
és különbözik az azonos nevű változóktól a külső szkriptben.
A fentiek a helyes módszerek egy tetszőleges komplex szkript meghívására a a következővel: find
. A find
használata olyan ciklusban, mint a
for pathname in $( find ... ); do
, hibára hajlamos és inelegáns (személyes vélemény). A fájlnevek felosztása a szóközökön, a fájlnév rángatása, és a héjat arra is kényszeríti, hogy bővítse a find
teljes eredményét, mielőtt még a ciklus első iterációját lefuttatná.
Lásd még:
A -exec ... {} +
A végén található ;
helyettesíthető a következővel: +
. Ez azt eredményezi, hogy find
az adott parancsot a lehető legtöbb argumentummal (megtalált elérési utak) hajtja végre, nem pedig minden egyes megtalált útvonalnévnél. A {}
karakterláncnak közvetlenül a +
előtt kell szerepelnie, hogy működjön .
find . -type f -name "*.txt" \ -exec grep -q "hello" {} ";" \ -exec cat {} +
Itt a find
összegyűjti a kapott útvonalneveket és végrehajtja a cat
a lehető legtöbbre egyszerre.
find . -type f -name "*.txt" \ -exec grep -q "hello" {} ";" \ -exec mv -t /tmp/files_with_hello/ {} +
Hasonlóképpen, itt a mv
is végrehajtásra kerül lehetőleg néhányszor. Ez az utolsó példa megköveteli a GNU mv
parancsot a coreutils-tól (amely támogatja a -t
opciót).
A -exec sh -c ... {} +
szintén hatékony módja annak, hogy önkényesen összetett szkript segítségével hurkoljon egy útvonalnévhalmazon.
Az alapok megegyeznek a -exec sh -c ... {} ";"
, de a szkript most sokkal hosszabb argumentumlistát vesz fel. Ezeket át lehet hurkolni a "$@"
átkapcsolásával a szkript belsejében.
Példánk a fájlnév utótagokat megváltoztató utolsó szakaszról:
from=text # Find files that have names like something.text to=txt # Change the .text suffix to .txt find . -type f -name "*.$from" -exec sh -c " from=$1; to=$2 shift 2 # remove the first two arguments from the list # because in this case these are *not* pathnames # given to us by find for pathname do # or: for pathname in "$@"; do mv "$pathname" "${pathname%.$from}.$to" done" sh "$from" "$to" {} +
A -execdir
használata van még -execdir
( a legtöbb find
változat megvalósítja, de nem szabványos opció).
Ez úgy működik, mint a -exec
, azzal a különbséggel, hogy az adott shell parancsot a megtalált útvonal könyvtárának aktuális munkakönyvtáraként kell végrehajtani, és hogy A “7b5b2eccc1”> a megtalált elérési út basenime-jét tartalmazza, annak útja nélkül (de a GNU find
továbbra is a ./
, míg a BSD find
nem fogja megtenni).
Példa:
find . -type f -name "*.txt" \ -execdir mv {} done-texts/{}.done \;
Ez minden megtalált *.txt
-fájlt egy már létező done-texts
alkönyvtárba helyez át ugyanabban a könyvtárban, mint ahol a fájl volt. talált ra. A fájlt át fogják nevezni úgy is, hogy hozzáadják a .done
utótagot.
Ez kicsit bonyolultabb lenne a -exec
, mivel a megtalált fájl alapnevét ki kellene szereznünk a {}
ből a fájl új nevének kialakításához. Szükségünk van a {}
könyvtárnévre is a done-texts
könyvtár megfelelő megtalálásához.
-execdir
, néhány ilyen dolog könnyebbé válik.
A megfelelő művelet -exec
használatával -execdir
gyermekhéjat kell alkalmaznia:
find . -type f -name "*.txt" -exec sh -c " for name do mv "$name" "$( dirname "$name" )/done-texts/$( basename "$name" ).done" done" sh {} +
vagy,
find . -type f -name "*.txt" -exec sh -c " for name do mv "$name" "${name%/*}/done-texts/${name##*/}.done" done" sh {} +
Megjegyzések
-
-exec
vesz egy programot és argumentumokat és futtatja azokat; Néhány shell parancs csak programból és argumentumokból áll, de sokan nem. A shell parancs tartalmazhat átirányítást és csövezést; A-exec
nem lehet (bár az egészfind
átirányítható). A shell parancs használhatja a; && if
stb .; A-exec
nem képes, bár a-a -o
képes rá. A shell parancs lehet álnév vagy shell függvény, vagy beépített;-exec
nem tudja. A shell parancs kibővítheti a varsokat; A-exec
nem tud (bár afind
futtató külső héj is). A shell parancs minden alkalommal másképp helyettesítheti a$(command)
t;-exec
nem tudja. … - A ‘ sa shell parancs kimondása itt helytelen,
find -exec cmd arg \;
nem ‘ t héjat hív meg a shell parancssor értelmezéséhez, az közvetlenül aexeclp("cmd", "arg")
parancsot futtatja, nem pedigexeclp("sh", "-c", "cmd arg")
(amelyhez a A shell végül aexeclp("cmd", "arg")
megfelelőjét fogja megtenni, ha acmd
nem épül be). - Tisztázhatja, hogy az összes a
find
argumentumok-exec
után és legfeljebb;
vagy töltse ki a végrehajtandó parancsot az argumentumaival együtt, egy{}
argumentum minden egyes példányát az aktuális fájlra cserélve (;
), és a{}
, mint a+
előtti utolsó argumentum, amelyet külön argumentumként a fájlok listájával helyettesítenek (a{} +
eset). Az IOW-exec
több argumentumot vesz fel, amelyeket egy;
vagy{}
+
. - @Kusalananda Nem lenne ‘ t, az utolsó példád is ezzel az egyszerűbb paranccsal működik:
find . -type f -name '*.txt' -exec sh -c "mv $1 $(dirname $1)/done-texts/$(basename $1).done" sh {} ';'
? - @Atralb Igen, ez szintén működött és ugyanolyan hatást váltott ki, mint az utolsó kódrészlet, de a egy ciklusban, megtalált fájlonként egyszer végrehajtja a
sh
és amv
fájlokat minden megtalált fájlhoz, amelyek észrevehetően lassabb nagy mennyiségű fájl esetén.
man
oldalon is olvasható Egy segédprogram_neve vagy argumentuma csak a két karaktert tartalmazza ” {} ” d az aktuális útnév vel, ami számomra elégségesnek tűnik. Ezenkívül a-exec rm {} \;
példával is rendelkezik, akárcsak a kérdésében. Napjaimban alig volt más erőforrás, mint a ” nagy szürke fal “, nyomtatott könyvekman
oldalak (a papír élénkebb volt, mint a tároló). Tehát tudom, hogy ez elegendő ahhoz, hogy valaki új legyen a témában. Az utolsó kérdésed azonban méltányos itt feltenni. Sajnos sem @Kusalananda, sem én magam nem tudok erre válaszolni.