-exec -vaihtoehdossa huomaan etsivänni jatkuvasti sanan
find . -name "FILENAME" -exec rm {} \;
lähinnä siksi, että en näe, kuinka -exec
-osa toimii. Mitä ovat aaltosulkeet, vinoviiva ja puolipiste? Onko muita käyttötapoja että syntaksia?
Kommentit
vastaus
Tämä vastaus on seuraavissa osissa:
- Käyttäjän
-exec
- peruskäyttö
-exec
-yhdistelmänsh -c
-
-exec ... {} +
- -toiminnon käyttäminen
-execdir
-exec
-asetuksen
-exec
-vaihtoehto vie ulkoisen apuohjelman valinnaisilla argumenteilla sen argumentti ja suorittaa sen.
Jos merkkijono {}
on missä tahansa annetussa komennossa, kukin sen esiintymä korvataan parhaillaan käsiteltävällä polunimellä ( esim. ./some/path/FILENAME
). Useimmissa kuorissa kahta merkkiä {}
ei tarvitse lainata.
Komento on lopetettava ;
-merkillä find
, jotta tiedetään, mihin se päättyy (koska jälkikäteen voi olla muita vaihtoehtoja) s). Suojaamaan ;
kuorelta, se on lainattava nimellä \;
tai ";"
, muuten kuori näkee sen find
-komennon lopussa.
Esimerkki (\
Kahden ensimmäisen rivin loppu on vain rivin jatkoa varten:
find . -type f -name "*.txt" \ -exec grep -q "hello" {} ";" \ -exec cat {} ";"
Tämä löytää kaikki tavalliset tiedostot (-type f
) joiden nimet vastaavat mallia *.txt
nykyisessä hakemistossa tai sen alapuolella. Sen jälkeen se testaa, esiintyykö merkkijono hello
missään löydetyistä tiedostoista käyttämällä grep -q
-tekstiä (joka ei tuota mitään lähtöä, vain poistumista Tila). Merkkijonon sisältäville tiedostoille suoritetaan cat
, jotta tiedoston sisältö tulostetaan päätelaitteelle.
Jokainen -exec
toimii myös ”testinä” find
-nimisten polkujen nimissä, aivan kuten -type
ja -name
tekee. Jos komento palauttaa nollan poistumistilan (mikä tarkoittaa ”menestystä”), find
-komennon seuraava osa otetaan huomioon, muuten find
komento jatkuu seuraavalla polun nimellä. Tätä käytetään yllä olevassa esimerkissä tiedostojen löytämiseen, jotka sisältävät merkkijonon hello
, mutta ohitetaan kaikki muut tiedostot.
Yllä oleva esimerkki kuvaa kahta yleisintä käyttöä -exec
-tapauksia:
- Testinä haun rajoittamiseksi edelleen.
- Suorittaa jonkinlainen toiminta löydetyllä polun nimi (yleensä, mutta ei välttämättä, komennon
find
lopussa).
-exec
yhdessä sh -c
Komento, jonka -exec
voi suorittaa, on rajoitettu ulkoiseen apuohjelmaan valinnaisilla argumenteilla.Shellin sisäisten sisäänrakennusten, funktioiden, ehdollisten, putkilinjojen, uudelleenohjausten jne. Käyttäminen -exec
: n kanssa ei ole mahdollista, ellei sitä ole kääritty mihinkään sh -c
lapsikuori.
Jos vaaditaan bash
-ominaisuuksia, käytä bash -c
-kohtaa sh -c
.
sh -c
suorittaa /bin/sh
komentorivillä annetun komentosarjan kanssa, ja sen jälkeen valinnaiset komentoriviargumentit kyseiseen komentosarjaan.
Yksinkertainen esimerkki sh -c
-sovelluksen käytöstä itse ilman find
:
sh -c "echo "You gave me $1, thanks!"" sh "apples"
Tämä välittää kaksi argumenttia alijärjestelmän komentosarjalle. Nämä sijoitetaan komentoihin $0
ja $1
, jotta komentosarja voi käyttää niitä.
-
merkkijono
sh
. Tämä on käytettävissä muodossa$0
komentosarjan sisällä, ja jos sisäinen kuori antaa virheilmoituksen, se lisää sen etuliitteeseen tällä merkkijonolla. -
Argumentti
apples
on käytettävissä komentosarjassa nimellä$1
, ja jos argumentteja olisi ollut enemmän, nämä olisivat olleet käytettävissä nimellä$2
,$3
jne. Ne olisivat käytettävissä myös luettelossa"$@"
(paitsi$0
, joka ei olisi osa"$@"
).
Tämä on hyödyllistä yhdessä -exec
: n kanssa, koska sen avulla voimme tehdä mielivaltaisesti monimutkaisia komentosarjoja, jotka vaikuttavat find
: n löytämiin polkuihin.
Esimerkki: Etsi kaikki tavalliset tiedostot, joilla on tietty tiedostonimen loppuliite, ja muuta tiedostonimen pääte joksikin muuksi loppuliitteeksi, jossa loppuliitteet säilytetään muuttujina:
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" {} ";"
Sisällä rnal-komentosarja, $1
olisi merkkijono text
, $2
merkkijono txt
ja $3
olisi mikä tahansa polun nimi, jonka find
on löytänyt meille. Parametrin laajennus ${3%.$1}
ottaisi polun nimen ja poistaisi siitä loppuliitteen .text
.
Tai käyttämällä dirname
/ basename
:
find . -type f -name "*.$from" -exec sh -c " mv "$3" "$(dirname "$3")/$(basename "$3" ".$1").$2"" sh "$from" "$to" {} ";"
tai lisätyillä muuttujilla sisäinen komentosarja:
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" {} ";"
Huomaa, että tässä viimeisessä muunnoksessa muuttujat from
ja to
alikäytössä ovat erillään muuttujista, joilla on sama nimi ulkoisessa komentosarjassa.
Edellä on oikea tapa kutsua mielivaltainen monimutkainen komentosarja kohteesta -exec
ja find
. find
-silmukan käyttäminen sellaisessa silmukassa kuin
for pathname in $( find ... ); do
on virhealtista ja puuttuva (henkilökohtainen mielipide). Se on tiedostonimien jakaminen tyhjätiloissa, tiedostonimen huutaminen, ja pakottaa myös kuoren laajentamaan find
-tulosta ennen silmukan ensimmäisen iteroinnin suorittamista.
Katso myös:
- Miksi etsinnän haku ' -lähdön tulos on huono käytäntö?
- Onko mahdollista käyttää `find -exec sh -c` turvallisesti?
Käyttämällä -exec ... {} +
Lopussa oleva ;
voidaan korvata nimellä +
. Tämä saa find
suorittamaan annetun komennon mahdollisimman monilla argumenteilla (löydetyillä polkuilla) pikemminkin kuin kerran jokaiselle löydetylle polun nimelle. Merkkijonon {}
on oltava juuri ennen +
, jotta tämä toimisi .
find . -type f -name "*.txt" \ -exec grep -q "hello" {} ";" \ -exec cat {} +
Täällä find
kerää tuloksena olevat polunimet ja suorittaa cat
mahdollisimman monelle niistä kerralla.
find . -type f -name "*.txt" \ -exec grep -q "hello" {} ";" \ -exec mv -t /tmp/files_with_hello/ {} +
Samoin täällä mv
suoritetaan muutama kerta kuin mahdollista. Tämä viimeinen esimerkki vaatii GNU mv
coreutilsilta (joka tukee vaihtoehtoa -t
).
-exec sh -c ... {} +
on myös tehokas tapa siirtyä polkujen joukon yli mielivaltaisesti monimutkaisella komentosarjalla.
Perustiedot ovat samat kuin käytettäessä -exec sh -c ... {} ";"
, mutta komentosarja vie nyt paljon pidemmän luettelon argumenteista. Nämä voidaan kytkeä päälle siirtämällä komentosarjan "$@"
päälle.
Esimerkkimme viimeisestä osiosta, joka muuttaa tiedostonimen loppuliitteitä:
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" {} +
Käyttämällä -execdir
On myös -execdir
( useimmat find
muunnokset, mutta ei vakiovaihtoehto).
Tämä toimii kuten -exec
sillä erotuksella, että annettu komentokäsky suoritetaan löydetyn polun nimen hakemistolla sen nykyisenä työhakemistona ja että {}
sisältää löydetyn polun basename ilman polkua (mutta GNU find
etuliite silti basename ./
, kun taas BSD find
ei tee sitä).
Esimerkki:
find . -type f -name "*.txt" \ -execdir mv {} done-texts/{}.done \;
Tämä siirtää kaikki löydetyt *.txt
-tiedostot olemassa olevaan done-texts
alihakemistoon samassa hakemistossa kuin missä tiedosto oli löytyi . Tiedosto nimetään myös uudelleen lisäämällä siihen loppuliite .done
.
Tämä olisi hieman hankalampaa tehdä tiedostoon -exec
, koska meidän pitäisi saada löydetyn tiedoston basename ulos {}
muodostaaksemme tiedoston uuden nimen. Tarvitsemme myös hakemistonimen osoitteesta {}
, jotta done-texts
-hakemisto löydetään oikein.
Kun -execdir
, jotkut tällaisista asioista ovat helpompia.
Vastaava toiminto, jossa -exec
käytetään -execdir
joutuisi käyttämään lapsikuorta:
find . -type f -name "*.txt" -exec sh -c " for name do mv "$name" "$( dirname "$name" )/done-texts/$( basename "$name" ).done" done" sh {} +
tai,
find . -type f -name "*.txt" -exec sh -c " for name do mv "$name" "${name%/*}/done-texts/${name##*/}.done" done" sh {} +
Kommentit
-
-exec
ottaa ohjelman ja argumentit ja suorittaa sen; jotkut shell-komennot koostuvat vain ohjelmasta ja argumenteista, mutta monet eivät. Kuorikomento voi sisältää uudelleenohjauksen ja putkiston;-exec
ei voida (vaikka kokofind
voidaan ohjata uudelleen). Shell-komento voi käyttää; && if
jne;-exec
ei voi, vaikka-a -o
voi tehdä joitain. Shell-komento voi olla alias tai shell-toiminto tai sisäänrakennettu;-exec
ei voi. Kuorikomento voi laajentaa varsia;-exec
ei (vaikka ulompi kuori, joka suorittaafind
, voi. Kuorikomento voi korvata$(command)
joka kerta eri tavalla;-exec
ei voi. … - Sen sanominen ' sa-komento on väärä,
find -exec cmd arg \;
ei ' t kutsu kuori tulkitsemaan kuoren komentoriviä, se suorittaaexeclp("cmd", "arg")
suoraan, eiexeclp("sh", "-c", "cmd arg")
(jolle shell lopulta tekisi vastaavanexeclp("cmd", "arg")
, joscmd
ei olisi rakennettu). - Voit selventää, että kaikki
find
-argumentit-exec
– ja;
tai muodostavat komennon, joka suoritetaan yhdessä sen argumenttien kanssa, jolloin{}
-argumentin kukin esiintymä korvataan nykyisellä tiedostolla (;
viimeisenä argumenttina ennen +
korvattu tiedostoluettelolla erillisinä argumentteina ({} +
tapaus). IOW -exec
vie useita argumentteja, jotka päättyvät ;
tai {}
+
.
find . -type f -name '*.txt' -exec sh -c "mv $1 $(dirname $1)/done-texts/$(basename $1).done" sh {} ';'
? mv
silmukassa, kerran löydettyä tiedostoa kohti, suoritat sekä sh
että mv
jokaiselle löydetylle tiedostolle, jotka huomattavasti hitaampi suurille tiedostomäärille.
man
-sivulla lukee apuohjelman_nimi tai argumentti sisältää vain kaksi merkkiä " {} " korvataan d nykyisellä polunimellä , joka näyttää olevan riittävä minulle. Lisäksi siinä on esimerkki-exec rm {} \;
, aivan kuten kysymyksessäsi. Minun päivinäni oli tuskin muita resursseja kuin " iso harmaa seinä ", kirjat painetuillaman
sivut (paperi oli nopeampi kuin varastointi). Joten tiedän, että tämä riittää jollekin uudelle aiheelle. Viimeinen kysymyksesi on kuitenkin oikeudenmukainen esittää täällä. Valitettavasti @Kusalanandalla ja minulla ei ole vastausta siihen.