-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

  • @Philippos: Ymmärrän mielipiteesi. Muista, että man-sivut ovat viitteellisiä eli hyödyllisiä niille ymmärtämällä asia etsimään syntaksia. Jos joku uusi aiheeseen liittyy, hän on usein salaperäinen ja muodollinen, jotta siitä olisi hyötyä. Tulet huomaamaan, että hyväksytty vastaus on noin 10 kertaa niin pitkä kuin man-sivun merkintä, ja että ' s syystä.
  • Jopa vanhalla POSIX 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 painetuilla man 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.
  • @Philippos 🙂 Voi, että olisi jännittävä kokeilla " jännittävä ", joka on minun kaavion mittakaavan ulkopuolella.
  • Comeon @Philippos. Sanotko todella Kusalanandalle, että hän ei parantanut manpageja? 🙂
  • @ZsoltSzilagy En sanonut sitä enkä tarkoittanut sitä. Hän ruokki sinua hyvin, luulen vain, että olet tarpeeksi vanha syömään itse. (-;

vastaus

Tämä vastaus on seuraavissa osissa:

  • Käyttäjän -exec
  • peruskäyttö -exec -yhdistelmän sh -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:

  1. Testinä haun rajoittamiseksi edelleen.
  2. 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ä.

  1. 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.

  2. 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:


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 koko find 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 suorittaa find, 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 suorittaa execlp("cmd", "arg") suoraan, ei execlp("sh", "-c", "cmd arg") (jolle shell lopulta tekisi vastaavan execlp("cmd", "arg"), jos cmd 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 {} +.

  • @Kusalananda Ei ' t, viimeinen esimerkkisi toimii myös tämän yksinkertaisemman komennon kanssa: find . -type f -name '*.txt' -exec sh -c "mv $1 $(dirname $1)/done-texts/$(basename $1).done" sh {} ';'?
  • @Atralb Kyllä, se olisi myös toiminut ja vaikuttanut samalla tavalla kuin viimeinen koodikappale, mutta sen sijaan, että suoritettaisiin mv silmukassa, kerran löydettyä tiedostoa kohti, suoritat sekä sh että mv jokaiselle löydetylle tiedostolle, jotka huomattavasti hitaampi suurille tiedostomäärille.
  • Vastaa

    Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *