Beveiligingsinformatieportaal. Xargs: meerdere gebruiksscenario's

Op lange winteravonden zat ik en dacht: "Als het daglicht komt, ga ik zitten en ga ik op de juiste manier om met dit mysterieuze xarg-hulpprogramma." Nou, het lijkt erop dat de tijd is gekomen - ik ging zitten om het uit te zoeken. Het eerste wat mij opviel was dat de man ervoor nogal mysterieus was en de zaken niet meteen duidelijk maakte. op Wikipedia voegde ook geen enkel inzicht toe, maar bracht mij zelfs in verwarring, dus besloot ik mijn eigen onderzoek uit te voeren en erover te schrijven kleine handleiding kleine jongen Zoals je weet, zul je het begrijpen als je het uitlegt :)

Dus, xargs.

xargs is een opdrachtregelhulpprogramma waarmee u elk commando kunt oproepen waarvan de argumenten zijn overgenomen standaard invoer. Bovendien kunnen de argumenten in één keer worden doorgegeven, of kunnen ze in verschillende stukken worden gegroepeerd. We zullen xargs versie 4.4.0 bestuderen, en volgens de aanbeveling van de man zullen we alleen nieuwe argumenten gebruiken die niet als verouderd zijn gemarkeerd (het is beter om meteen te wennen aan correct werken).

Het eerste dat u moet begrijpen, is dus hoe xargs de binnenkomende stroom verwerkt en in argumenten verdeelt. Er zijn verschillende modi, afhankelijk van de opties:

1. Normaal. Standaard is het argumentscheidingsteken elk witruimteteken: spatie, tab, verticale tab of nieuwe regel. Maar zoals in commandoshell je kunt "" of \ gebruiken om het splitsen van argumenten te voorkomen.

2. Regelmatig, met groepering. Modus ingeschakeld door de parameter -L. Bijna identiek aan de vorige, behalve dat xargs onthoudt welk argument op welke regel staat. Bovendien, als de regel eindigt met een spatie of tab, volgende regel wordt beschouwd als een voortzetting van de huidige.

3. Regel voor regel. Ingeschakeld bij gebruik van de optie -I of -0. In dit geval wordt de hele tekenreeks als één geheel argument beschouwd, ondanks spaties en tabs erin. Voor -I is het einde van de regel het teken "\n" en voor -0 het teken "\0"

Laten we een paar tests doen om dit allemaal beter te begrijpen. Laten we een bestandstest maken met de volgende inhoud (== het is niet nodig om het bestand in te voeren):
==
arg1
arg2 spatie
"arg3 geciteerd"
arg4\ is ontsnapt
arg5 met
doorgaan
==
(Er moet een spatie staan ​​na "arg5 with")
We zullen ook een klein tp-script schrijven dat de argumenten zal uitvoeren, gescheiden door het symbool ":" en de hoeveelheid:
==
#!/bin/bash
echo -n "@$#"
terwijl [[ $1 != "" ]]; doe echo -n ":$1"; verschuiving; klaar
echo
==

Normale modus (argumenten gescheiden door witruimte):
x $ kattentest | xargs./tp
@8:arg1:arg2:spatie:arg3 geciteerd:arg4 ontsnapt:arg5:met:doorgaan
Het bestand werd opgesplitst in argumenten met behulp van witruimtetekens, maar de regels tussen aanhalingstekens en escape-tekens met het teken "\" bleven intact.

De normale modus met groeperen op rijen verschilt in dit stadium niet van de vorige.

Lijnsplitsing. Laten we een tweede testbestand maken met de volgende opdracht:
x $ cp test testz && printf "\0arg6" >> testz
Laten we het controleren
x $ kat testz | xargs -0 ./tp
@2:arg1
arg2 spatie
"arg3 geciteerd"
arg4\ is ontsnapt
arg5 met
doorgaan
:arg6

Zoals u kunt zien, zijn er slechts twee argumenten. De eerste is lang, met behoud van regeleinden, aanhalingstekens en \, en de tweede is arg6. In het bestand worden ze gescheiden door een null-teken.

Wat betreft de scheiding van parameters kan nog één ding worden gezegd over de optie -d, die een nieuw scheidingsteken specificeert. Laten we bijvoorbeeld '3' als scheidingsteken gebruiken.
x $ kattentest | xargs -d 3 ./tp
@2:arg1
arg2 spatie
"arg: geciteerd"
arg4\ is ontsnapt
arg5 met
doorgaan
Het bestand is opgedeeld in 2 delen op de plaats van het "3"-symbool. Het opmerkelijke is dat je op deze manier de optie -0 kunt emuleren
x $ kat testz | xargs -d "\x00" ./tp
@2:arg1
arg2 spatie
"arg3 geciteerd"
arg4\ is ontsnapt
arg5 met
doorgaan
:arg6

Het lijkt erop dat we de verdeling van de invoerstroom in argumenten hebben opgelost, laten we verder gaan met parametervervanging.

Dus na zijn opties wacht xarg op een commando dat het zal uitvoeren. Alle binnenkomende argumenten worden in groepen verdeeld, waarna opdracht gegeven wordt voor elke groep aangeroepen en alle argumenten uit die groep worden eraan doorgegeven.

Laten we nu eens kijken hoe groepen worden gevormd.

1. Als er geen opties zijn, dan is er maar één groep, alle argumenten uit de invoerstroom vallen daarin. Een groep van oneindige omvang, om zo te zeggen :)

2. De optie -L n specificeert groeperen op lijnen. Aan het commando worden argumenten doorgegeven op n regels. Ik zal het met voorbeelden demonstreren.
Groeperen op 1 regel:
x $ kattentest | xargs -L 1 ./tp
@1:arg1
@2:arg2:spatie
@1:arg3 geciteerd
@1:arg4 ontsnapt
@3:arg5:met:doorgaan
Je kunt zien dat de tweede regel 2 argumenten bevat, omdat ze allebei op dezelfde regel staan. En de laatste is eigenlijk 3, aangezien de voorlaatste regel “verlengd” is vanwege de ruimte aan het einde.

Groepeer nu op 2 regels. De opdracht bevat regels 1 en 2; 3 en 4; en wees 5e:
x $ kattentest | xargs -L 2 ./tp
@3:arg1:arg2:spatie
@2:arg3 geciteerd:arg4 is ontsnapt
@3:arg5:met:doorgaan

3. Groeperen op argumenten, gespecificeerd door de optie -n x. Alles is hier transparant: de argumenten worden gegroepeerd in x-stukken en doorgegeven aan de opdracht.
Voor één argument:
x $ kattentest | xargs -n 1 ./tp
@1:arg1
@1:arg2
@1: spatie
@1:arg3 geciteerd
@1:arg4 ontsnapt
@1:arg5
@1: met
@1: ga door
Elk 2 argumenten:
x $ kattentest | xargs -n 2 ./tp
@2:arg1:arg2
@2:spatie:arg3 geciteerd
@2:arg4 ontsnapt:arg5
@2:met:doorgaan

3. Vervangingsmodus - optie -I. Om te beginnen moeten we dat in herinnering brengen deze modus Argumenten uit de invoerstroom worden anders geparseerd. Elke regel is één geheel argument; regels worden niet aaneengeschakeld. Ten tweede heeft de optie -I een parameter: een string, die in de opdracht wordt vervangen door een argument:
x $ echo -e "A B\nC D" | xargs -I _ ./tp =_+_=
@1:=A B+A B=
@1:=C D+C D=
Het is gemakkelijk op te merken dat het teken _ is opgegeven als een argumentvervangingsreeks, die twee keer in de opdracht wordt gebruikt. U kunt ook zien dat de argumenten als hele regels worden toegewezen en dat de spatie geen invloed heeft op het parseren. Het commando wordt voor elk argument aangeroepen.

Dat is alles met vervanging. Laten we eens kijken naar de resterende belangrijke opties
-r - voer de opdracht niet uit als er geen argumenten zijn:
x $ cat /dev/null | xargs./tp
@0
x $ cat /dev/null | xargs -r./tp
x$
Zoals u kunt zien, werd de opdracht in het tweede geval niet uitgevoerd.

P - xargs zal om bevestiging vragen om elke opdracht uit te voeren.

Hiermee is de korte tutorial voltooid. Het bleek niet heel kort te zijn, maar ik hoop dat het begrijpelijk was;)

Vermijd slechte UNIX-praktijken

Vaak raken we, met welk systeem dan ook, gewend aan bepaalde werkpatronen. Maar deze sjablonen zijn niet altijd optimaal. Soms ontwikkelen we zelfs slechte gewoonten die tot rommel en onhandigheid op het werk leiden. Een van de beste manieren Door dergelijke tekortkomingen te corrigeren, ontwikkel je de gewoonte om goede technieken te gebruiken die rommel voorkomen. Dit artikel biedt 10 methoden om met teamwerk te werken UNIX-reeks waardevolle gewoonten die u zullen helpen veel voorkomende tekortkomingen te vermijden en uw werkefficiëntie te verbeteren. Gedetailleerde beschrijving Elk van de methoden wordt na de lijst gegeven.

Laten we 10 goede gewoonten leren

Tien goede methoden om aan te wennen:

Maak directorystructuren met één opdracht

Lijst 1 illustreert een van de meest voorkomende UNIX-fouten: het stap voor stap specificeren van een directorystructuur.

Lijst 1. Voorbeeld slechte methode Taak #1: Stap-voor-stap definitie van een directorystructuur
~ $ mkdir tmp ~ $ cd tmp ~/tmp $ mkdir a ~/tmp $ cd a ~/tmp/a $ mkdir b ~/tmp/a $ cd b ~/tmp/a/b/ $ mkdir c ~/tmp /a/b/ $ cd c ~/tmp/a/b/c $

Het is veel sneller om de optie -p mkdir te gebruiken en met één opdracht alle bovenliggende en onderliggende mappen te maken. Maar zelfs beheerders die deze optie kennen, werken nog steeds stap voor stap, waarbij ze elke submap afzonderlijk op de opdrachtregel maken. Bespaar tijd - wen er maar aan goede methoden:

Listing 2. Voorbeeld van goede werkmethode #1: Een directorystructuur definiëren met één commando
~ $ mkdir -p tmp/a/b/c

U kunt deze optie gebruiken om niet alleen een eenvoudige hiërarchie te maken, maar ook complexe mappenbomen, die erg handig zijn om in scripts te gebruiken. Bijvoorbeeld:

Lijst 3. Nog een voorbeeld van goede werkmethode nr. 1: Het definiëren van een complexe directorystructuur met één commando
~ $ mkdir -p project/(lib/ext,bin,src,doc/(html,info,pdf),demo/stat/a)

Voorheen was er slechts één reden om door een directorystructuur te stappen: de mkdir-implementatie ondersteunde deze optie niet, maar dit is op de meeste systemen niet langer relevant. IBM, AIX, mkdir, GNU mkdir en andere systemen die voldoen aan de UNIX-specificatie hebben nu deze optie.

Voor de weinige systemen die deze functie niet hebben, zou je het mkdirhier-script moeten gebruiken (zie ), dat mkdir omhult en dezelfde functie uitvoert.

~ $ mkdirhier project/(lib/ext,bin,src,doc/(html,info,pdf),demo/stat/a)

Verander paden; draag het archief niet over

Een andere slechte manier om te werken is door het archief-.tar-bestand naar een specifieke map te verplaatsen als je het archief naar die map wilt uitpakken. Dat moet je niet doen. Je kunt ze allemaal uitpakken archiefbestand.tar naar elke map - dit is waar de -C optie voor is. Gebruik de optie -C om de map op te geven die u wilt uitpakken:

Lijst 4: Voorbeeld van een goede oplossing #2: De optie -C gebruiken om een ​​.tar-archiefbestand uit te pakken
~ $ tar xvf -C tmp/a/b/c newarc.tar.gz

Het gebruik van de optie -C verdient de voorkeur boven het verplaatsen van het archiefbestand naar de gewenste map, het wijzigen van de map en het extraheren van de inhoud van het bestand - vooral als het archiefbestand zelf zich ergens anders bevindt.

Combineer uw opdrachten met controle-instructies

Je weet waarschijnlijk al dat je in de meeste shells opdrachten op dezelfde opdrachtregel kunt combineren door er een puntkomma (;) tussen te gebruiken. De puntkomma is een shell-control-operator, en hoewel het de bedoeling is om meerdere afzonderlijke opdrachten aan één enkele opdrachtregel te koppelen, is het gebruik ervan niet altijd mogelijk. Stel dat u bijvoorbeeld een puntkomma gebruikt om twee opdrachten samen te voegen, waarbij de uitvoering van de tweede opdracht volledig afhankelijk is van de succesvolle voltooiing van de eerste. Als de eerste opdracht niet werkt zoals u verwacht, wordt de tweede opdracht nog steeds uitgevoerd - en mislukt. Gebruik in plaats daarvan een geschiktere controleverklaring (sommige worden in dit artikel beschreven). Als je schild ze ondersteunt, zullen ze even wennen zijn.

Voer een opdracht alleen uit als een andere opdracht een nulwaarde retourneert

Gebruik de && control-operator om twee opdrachten zo te combineren dat de tweede opdracht alleen wordt uitgevoerd als de eerste terugkeert nulwaarde. Met andere woorden: als het eerste commando slaagt, wordt het tweede commando ook uitgevoerd. Als het eerste commando niet wordt uitgevoerd, wordt het tweede commando helemaal niet uitgevoerd. Bijvoorbeeld:

Lijst 5. Voorbeeld van goede praktijk nr. 3: Combineer commando's met controle-instructies
~ $ cd tmp/a/b/c && tar xvf ~/archive.tar

Dit voorbeeld extraheert de inhoud van het archief in de map ~/tmp/a/b/c, als die map bestaat. Als de map niet bestaat, wordt de opdracht tar niet uitgevoerd en wordt er niets uit het archief gehaald.

Voer een opdracht alleen uit als een andere opdracht een waarde retourneert die niet nul is

Op dezelfde manier is de besturingsoperator || scheidt de twee opdrachten en voert de tweede opdracht alleen uit als de eerste opdracht een waarde anders dan nul retourneert. Met andere woorden, als het eerste commando was succesvol, zal de tweede opdracht niet worden uitgevoerd. Als het eerste commando mislukt, dan het tweede zal beginnen. Deze operator wordt vaak gebruikt om te testen of een bepaalde directory bestaat, en zo niet, dan wordt deze aangemaakt:

Lijst 6. Nog een voorbeeld van goede praktijk nr. 3: Combineer commando's met controle-instructies
~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c

U kunt de in deze paragraaf beschreven controleverklaringen ook combineren. Elk van hen verwijst naar de laatste opdracht die werd uitgevoerd:

Lijst 7. Gecombineerd voorbeeld van goede praktijk nr. 3: Commando's combineren met controle-instructies
~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c &&

Wees voorzichtig met het gebruik van aanhalingstekens bij het werken met variabelen

Wees altijd voorzichtig met shell-uitbreiding en namen van variabelen. Eigenlijk is dit het goed idee- plaats verwijzingen naar variabelen alleen tussen dubbele aanhalingstekens als er geen speciale redenen zijn om dit niet te doen. Op dezelfde manier moet, als een variabelenaam onmiddellijk wordt gevolgd door alfanumerieke tekst, de naam van de variabele worden ingesloten beugel(()) om het te onderscheiden van de omringende tekst. Anders interpreteert de shell de afsluitende tekst als onderdeel van de variabelenaam - en het meest waarschijnlijke resultaat is dat ook nulcode opbrengst. Lijst 8 toont voorbeelden van het gebruik van aanhalingstekens met variabelenamen en de resultaten.

Opsomming 8. Voorbeeld van goede praktijk nr. 4: Het gebruiken (en niet gebruiken) van aanhalingstekens bij het werken met variabelen
~ $ ls tmp/ a b ~ $ VAR="tmp/*" ~ $ echo $VAR tmp/a tmp/b ~ $ echo "$VAR" tmp/* ~ $ echo $VARa ~ $ echo "$VARa" ~ $ echo "$(VAR)a" tmp/*a ~ $ echo $(VAR)a tmp/a ~ $

Gebruik een escape-reeks om een ​​lange tekenreeks in te voeren

Je hebt waarschijnlijk voorbeelden gezien van code waarbij een backslash (\) een lange regel voortzet, en je weet dat de meeste shells wat je typt op volgende regels, samengevoegd met een backslash, behandelen als één lange regel. U kunt echter meer voordeel halen uit deze opdrachtregelfunctie door deze vaker te gebruiken. De backslash is vooral handig als uw terminal niet goed omgaat met onderbrekingen van meerdere regels of als de opdrachtregel korter is dan normaal (bijvoorbeeld als u lange weg). Backslash is ook handig om delen van de betekenis te benadrukken. lange rij, zoals in het volgende voorbeeld:

Lijst 9. Voorbeeld van goede praktijk nr. 5: Backslashes gebruiken op lange strings
~ $ cd tmp/a/b/c || \ > mkdir -p tmp/a/b/c && \ > tar xvf -C tmp/a/b/c ~/archive.tar

Als alternatief is hier een andere configuratie die ook werkt:

Lijst 10. Een alternatief voorbeeld van goede praktijk nr. 5: Backslashes gebruiken op lange strings
~ $ cd tmp/a/b/c \ > || \ > mkdir -p tmp/a/b/c \ > && \ > tar xvf -C tmp/a/b/c ~/archive.tar

Wanneer u een string in meerdere regels opsplitst, behandelt de shell deze altijd als één hele string, waarbij alle backslashes en extra spaties uit de resulterende lange string worden verwijderd.

Opmerking: Wanneer u in de meeste shells op de pijl-omhoog drukt, wordt de gehele meerregel weergegeven als een enkele lange lijn.

Combineer opdrachten in een lijst

Met de meeste shells kun je sets commando's combineren in een lijst; op deze manier kun je werk van het ene team naar het andere overbrengen of op een andere manier omleiden. U kunt dit doorgaans doen door een lijst met opdrachten uit te voeren in een alternatieve of huidige shell.

Een lijst met opdrachten uitvoeren in een extra shell

Gebruik haakjes om een ​​lijst met opdrachten in één groep te plaatsen. Hierdoor kunt u opdrachten in een extra shell uitvoeren en de uitvoer ervan omleiden of anderszins verzamelen, zoals weergegeven in het volgende voorbeeld:

Lijst 11. Voorbeeld van goede praktijk nr. 6: Een lijst met opdrachten uitvoeren in een extra shell
~ $ (cd tmp/a/b/c/ || mkdir -p tmp/a/b/c && \ > VAR=$PWD; cd ~; tar xvf -C $VAR archief.tar) \ > | mailx admin -S "Inhoud archiveren"

Dit voorbeeld extraheert de inhoud van het archief naar de map tmp/a/b/c, terwijl de uitvoer van de gegroepeerde opdrachten, inclusief een lijst met uitgepakte bestanden, wordt verzonden naar beheerdersadres.

Het gebruik van extra wrappers is handig in gevallen waarin u deze overschrijft omgevingsvariabelen in de opdrachtenlijst en u wilt deze wijzigingen in uw huidige shell niet accepteren.

Voer een lijst met opdrachten uit in de huidige shell

Gebruik accolades (()) om een ​​lijst met opdrachten in te sluiten die moeten worden uitgevoerd huidig schelp. Zorg ervoor dat u spaties tussen haakjes en opdrachten toevoegt, omdat... anders interpreteert de shell de haakjes mogelijk verkeerd. Zorg er ook voor dat de laatste opdracht in de lijst wordt gevolgd door een puntkomma (;), zoals in het volgende voorbeeld:

Lijst 12. Nog een voorbeeld van goede praktijk nr. 6: Een lijst met opdrachten uitvoeren in de huidige shell
~ $ ( cp $(VAR)a . && chown -R gast.gast a && \ > tar cvf newarchive.tar a; ) | mailx admin -S "Nieuw archief"

Pas xargs toe om zoekresultaten te vinden

Gebruik de opdracht xargs als filter om te werken met de lijst met bestanden die wordt geretourneerd door te zoeken met de opdracht find. Normaal gesproken retourneert de opdracht find een lijst met bestanden die aan bepaalde criteria voldoen. Deze lijst wordt doorgegeven aan xargs, die andere bewerkingen uitvoert met behulp van de lijst met bestanden als argumenten, zoals in het volgende voorbeeld:

Lijst 13. Voorbeeld van een klassiek gebruik van de opdracht xargs
~$vind | \>xargs

Denk echter niet dat xargs slechts een toevoeging is om te vinden; Dit is een van die tools waarmee je, als je er eenmaal aan gewend bent, er constant mee wilt werken, bijvoorbeeld in de volgende gevallen:

Een lijst doorgeven, gescheiden door spaties

In deze eenvoudige illustratie is xargs als een filter dat als invoer een lijst neemt (elk element op een afzonderlijke regel) en de elementen ervan op een enkele regel plaatst, gescheiden door spaties:

Lijst 14. Voorbeelduitvoer van de xargs-opdracht
~ $ xargsabc a b c ~ $

U kunt de uitvoer van elk hulpprogramma dat bestandsnamen uitvoert via xargs verzenden om een ​​lijst met argumenten op te halen voor een aantal andere hulpprogramma's die bestandsnamen als argument gebruiken, zoals in het volgende voorbeeld:

Lijst 15. Voorbeeld van het gebruik van de opdracht xargs
~/tmp $ls-1 | xargs December_Report.pdf LEESMIJ a archive.tar mkdirhier.sh ~/tmp $ ls -1 | xargs-bestand December_Report.pdf: PDF-document, versie 1.3 README: ASCII-tekst a: directory archive.tar: POSIX tar-archief mkdirhier.sh: Bourne shell-scripttekst uitvoerbaar ~/tmp $

De opdracht xargs is nuttig voor meer dan alleen het doorgeven van bestandsnamen. Gebruik het elke keer dat u tekst op één regel wilt filteren:

Lijst 16. Voorbeeld van goede praktijk nr. 7: De xargs-tool gebruiken om tekst op één regel te filteren
~/tmp $ ls -l | xargs -rw-r--r-- 7 joe joe 12043 27 januari 20:36 December_Report.pdf -rw-r--r-- 1 \ root root 238 03 december 08:19 LEESMIJ drwxr-xr-x 38 joe joe 354082 02 november \ 16:07 a -rw-r--r-- 3 joe joe 5096 14 december 14:26 archive.tar -rwxr-xr-x 1 \ joe joe 30 september 12:40 mkdirhier.sh ~/ tmp$

Wees voorzichtig bij het gebruik van xargs

Technisch gezien zijn er zeldzame gevallen waarin het gebruik van xargs problematisch kan zijn. Standaard is het teken voor het einde van het bestand het onderstrepingsteken (_); als dit teken als enige argument werd doorgegeven, wordt alles erna genegeerd. Gebruik uit voorzorg de vlag -e, die zonder argumenten het einde-van-bestand-teken uitschakelt.

Weet wanneer je grep moet gebruiken om te tellen - en wanneer je het moet vermijden

Vermijd het gebruik van wc -l na grep om het aantal ontvangen regels te tellen. Met de optie -c voor grep kunt u het aantal regels tellen dat overeenkomt met bepaalde patronen en is deze over het algemeen sneller dan de combinatie "wc after grep", zoals in het volgende voorbeeld:

Listing 17. Voorbeeld van goede werkmethode #8: Het aantal regels tellen met en zonder grep
~ $ tijd grep en tmp/a/longfile.txt | wc -l 2811 echt 0m0.097s gebruiker 0m0.006s sys 0m0.032s ~ $ tijd grep -c en tmp/a/longfile.txt 2811 echt 0m0.013s gebruiker 0m0.006s sys 0m0.005s ~ $

De -c optie is op een goede manier tellen is niet alleen te danken aan de snelheidsfactor. Wanneer je meerdere bestanden gebruikt, retourneert grep met de optie -c een aparte waarde voor elk bestand, één op elke regel, terwijl de uitvoerrichting in wc geeft totaal resultaat voor alle bestanden.

Dit voorbeeld is echter niet alleen interessant vanuit het oogpunt van prestaties; het illustreert een andere veel voorkomende fout. Deze telmethode biedt alleen aantal regels waarin overeenkomsten met het patroon zijn gevonden- en goed als dat is wat je zoekt. Maar in gevallen waarin strings meerdere overeenkomsten met een bepaald patroon kunnen hebben, zullen deze methoden geen echte waarde opleveren aantal overeenkomsten met het patroon. Gebruik wc om het aantal wedstrijden te tellen. Voer om te beginnen grep uit met de optie -o als uw versie dit ondersteunt. Deze optie wordt weergegeven alleen patroon komt overeen, één voor elke lijn, maar niet de lijn zelf. Het kan niet worden gebruikt met de optie -c, dus gebruik wc -l om het aantal regels te tellen, zoals in het volgende voorbeeld:

Voorbeeld van goede praktijk #8: Het aantal overeenkomsten met een patroon tellen met grep
~ $ grep -o en tmp/a/longfile.txt | wc -l 3402 ~ $

In dit geval is het aanroepen van wc iets sneller dan het voor de tweede keer aanroepen van grep met een dummy-patroon, zodat elke regel kan worden vergeleken en geteld (zoals grep -c).

Vergelijking van specifieke uitvoervelden, niet alleen tekenreeksen

Een tool als awk verdient de voorkeur boven grep als je alleen een patroon wilt matchen specifieke velden uitvoerregels, niet de hele regel.

Het volgende vereenvoudigde voorbeeld laat zien hoe u alleen de bestanden sorteert die in december zijn gewijzigd:

Listing 19. Voorbeeld van slechte praktijk #9: grep gebruiken om een ​​patroon in specifieke velden te vinden
~/tmp $ ls -l /tmp/a/b/c | grep Dec -rw-r--r-- 7 joe joe 12043 Jan 27 20:36 December_Report.pdf -rw-r--r-- 1 root root 238 Dec 03 08:19 LEESMIJ -rw-r--r- - 3 joe joe 5096 14 december 14:26 archive.tar ~/tmp $

In dit voorbeeld filtert grep de regels en drukt alle bestanden af ​​die Dec in hun naam of wijzigingsdatum hebben. Een bestand als December_Report.pdf is dus prima, zelfs als het sinds januari niet meer is gewijzigd. Dit is misschien niet wat je wilt. Om een ​​patroon in een specifiek veld te matchen, is het beter om awk te gebruiken, waarbij de relatieve operator overeenkomt met een specifiek veld, zoals weergegeven in het volgende voorbeeld

Listing 20. Voorbeeld van een goede oplossing nr. 9: awk gebruiken om een ​​patroon in specifieke velden te vinden
~/tmp $ ls -l | awk "$6 == "Dec"" -rw-r--r-- 3 joe joe 5096 14 december 14:26 archive.tar -rw-r--r-- 1 root root 238 03 december 08:19 LEESMIJ ~ /tmp$

Meer details over met behulp van awk kunt u lezen in de rubriek.

Gebruik geen kattenuitgang doorgeven

Een fundamentele en veel voorkomende fout bij het gebruik van grep is het doorgeven van de uitvoer van cat aan grep om de inhoud van een enkel bestand te doorzoeken. Dit is een volkomen onnodige tijdverspilling omdat tools zoals grep bestandsnamen als argumenten gebruiken. Daarom is het in deze situatie absoluut niet nodig om kat te gebruiken, zoals in het volgende voorbeeld:

Listing 21. Voorbeeld van goede methode #10: grep gebruiken met en zonder cat.
~ $ tijd cat tmp/a/longfile.txt | grep en 2811 echte 0m0.015s gebruiker 0m0.003s sys 0m0.013s ~ $ tijd grep en tmp/a/longfile.txt 2811 echte 0m0.010s gebruiker 0m0.006s sys 0m0.004s ~ $

Deze fout wordt in veel gevallen gemaakt. Omdat de meeste tools standaardinvoer als argument gebruiken met een streepje (-), is zelfs het argument voor het gebruik van cat om talloze bestanden te diversifiëren met stdin vaak niet geldig. Eigenlijk is het noodzakelijk om eerst aaneenschakeling uit te voeren met behulp van kat met een van de verschillende filteropties.

Conclusie: Wen aan het goede

We hebben verschillende methoden bekeken om op de opdrachtregel te werken. Slechte gewoonten vertragen je werk en leiden vaak tot onverwachte fouten. Dit artikel deelt 10 nieuwe technieken die je kunnen helpen veel van de meest voorkomende fouten weg te nemen. Raak gewend aan deze goede technieken en verbeter uw rijvaardigheid. opdrachtregel Unix.

xargs- een hulpprogramma voor het genereren van een lijst met argumenten en het uitvoeren van een opdracht. Dat wil zeggen, met xargs kunt u elk commando met argumenten aanroepen. De xargs-opdracht bestaat uit twee componenten. Eerst moet u de bestanden opgeven die u interesseren. Ten tweede moet u de opdracht of het script opgeven dat u op elk van deze bestanden wilt toepassen.

xargs - splitst de invoerstroom in argumenten en geeft de uitvoering ervan door aan elk commando (standaard echo). Leest ofwel van standaard invoer, of via pijp.

xargs-verwerkingsmodi voor inkomende gegevens

    Standaard is het argumentscheidingsteken elk witruimteteken: spatie, tab, verticale tab of nieuwe regel. Maar net als in de opdrachtshell kunt u "" of \ gebruiken om het splitsen van argumenten te voorkomen.

    Modus ingeschakeld door de parameter -L. Bijna identiek aan de vorige, behalve dat xargs onthoudt welk argument op welke regel staat. Bovendien, als een regel eindigt met een spatie of tab, wordt de volgende regel beschouwd als een voortzetting van de huidige.

    Regel voor regel. Ingeschakeld bij gebruik van de optie -I of -0. In dit geval wordt de hele tekenreeks als één geheel argument beschouwd, ondanks spaties en tabs erin. Voor -I is het einde van de regel het teken "\n" en voor -0 het teken "\0"

    Voorbeeld: Zoek in /home/user1 naar alle bestanden waarvan de naam eindigt op ".txt" en kopieer deze naar een andere map. zoek /home/user1 -naam "*.txt" | xargs cp -av --target-directory=/home/backup/ --parents

    Zoek een exemplaar van de zin logon home in alle bestanden in de map /etc/samba. $ vind /etc/samba | xargs grep -ni "inloggen thuis"

    Verwijder de lijst met bestanden. Bestandspaden worden regel voor regel geschreven in het bestand delfiles.txt xargs rm< delfiles.txt

Er is veel geschreven over het hulpprogramma xargs - wat kan er nog meer worden geschreven? Maar als je, zoals ze zeggen, dieper graaft, blijkt dat veel publicaties alleen de basisbeginselen schetsen, maar het belangrijkste missen: ze leggen niet uit hoe xargs in de echte praktijk kunnen worden gebruikt. Helaas zijn er maar heel weinig artikelen waarin complexe en niet-triviale opties voor het gebruik van deze tool worden geanalyseerd, wat erg handig is voor een systeembeheerder. Daarom hebben we ons artikel geschreven en geprobeerd zoveel mogelijk voorbeelden op te nemen van het gebruik van xargs om verschillende problemen op te lossen.

Eerst zullen we bekijken hoe xargs werkt en eenvoudigere voorbeelden analyseren, en vervolgens doorgaan met het analyseren van complexe en interessante gevallen.

Laten we de basis onthouden

De manier waarop xargs werkt kan als volgt worden beschreven: een programma haalt gegevens uit standaardinvoer of uit een bestand, splitst deze op volgens gespecificeerde parameters en geeft deze vervolgens als argument door aan een ander programma.

Over het algemeen kan de syntaxis van de xargs-opdracht als volgt worden weergegeven:

[lijst_generator_command] | xargs [xargs_options] [opdracht]
Laten we eens kijken hoe het allemaal werkt met behulp van eenvoudige voorbeelden en schoolvoorbeelden.

Bestanden verwijderen

Een van de meest voorkomende situaties waarin xargs wordt gebruikt, is het verwijderen van bestanden die zijn gevonden met de opdracht find.

Laten we ons de volgende situatie voorstellen: er is een map waarin groot aantal bestanden. U moet er bestanden uit verwijderen bepaald type(in ons voorbeeld - bestanden met de extensie *.sh). Om deze bewerking uit te voeren, moet u de uitvoer van het find-commando doorgeven aan xargs, en het -rm-commando zal worden toegepast op bestanden met de opgegeven extensie:

$ ls één.sh één.py twee.sh twee.py $ zoek . -naam "*.sh"| xargs rm -rf $ ls one.py twee.py

Merk op dat de bewerking van het verwijderen van bestanden kan worden uitgevoerd zonder xargs, maar met behulp van de opdracht

$vind. -naam "*.sh" -exec rm -rf "()" \

De beschreven methode werkt niet als de naam van een van de te verwijderen bestanden een spatie bevat. Een naam die bestaat uit twee woorden, gescheiden door een spatie, wordt niet als één geheel geaccepteerd.

Laten we dit illustreren met het volgende voorbeeld:

$ ls nieuw bestand.sh one.sh one.py two.sh two.py $ find . -naam "*.sh"| xargs rm -rf $ ls nieuw bestand.sh one.py two.py

Zoals u kunt zien, is het bestand met een spatie in de naam niet verwijderd.

Om dit probleem op te lossen, gebruikt u de optie print0 voor de opdracht find en de optie -0 voor de opdracht xargs. Het vervangt het standaard scheidingsteken (regeleinde met een nulteken (\x0), wat het einde van de opgeslagen tekenreeks betekent:

$vind. -naam "*.sh" -print0 | xargs -0 rm -rf

Xargs kan bijvoorbeeld ook helpen om alles snel te verwijderen tijdelijke bestanden met tmp-extensie:

$ vind /tmp -naam "*.tmp"| xargs rm

Bestandscompressie

U kunt alle bestanden in de huidige map comprimeren met gzip door de volgende opdracht in te voeren:

$ls | xargs -p -l gzip

Laten we een ander voorbeeld bekijken: alle bestanden met de extensie *.pl comprimeren met tar:

$vind. -naam "*.pl" | xargs tar -zcf pl.tar.gz

Bestanden hernoemen

Met xargs kun je dat doen massaal hernoemen bestanden. Laten we ons voorstellen dat we een groep bestanden hebben met de extensie *.txt, en we moeten deze extensie vervangen door *.sql. Dit kan worden gedaan met behulp van xargs en tekststreaming sed-editor:

$ls | sed -e "p;s/.txt$/.sql/" | xargs-n2 fmv

Als gevolg van de uitvoering ervan wordt een lijst met hernoemde bestanden op de console weergegeven.

Met xargs kun je ook toevoegen aan aanvullende elementen naar bestandsnamen (bijvoorbeeld datum):

$ls | xargs -I BESTAND mv()<...>-{}

In plaats van<..>je kunt alles vervangen wat je wilt.
De accolades () in dit voorbeeld betekenen het "huidige argument" (d.w.z. de huidige bestandsnaam).

Machtigingen voor mappen en bestanden wijzigen

Met behulp van xargs kunt u ook het proces van het wijzigen van machtigingen voor bestanden en mappen versnellen specifieke gebruiker of groepen. Laten we zeggen dat we alle mappen moeten vinden root-gebruiker en hun eigenaar vervangen door uitzendkracht. Deze bewerking wordt uitgevoerd met behulp van het commando:

$vind. -groepswortel -print | xargs chown-temp

Om alle mappen van de hoofdgroep te vinden en de groep te vervangen door temp, gebruik je de opdracht:

$vind. -groepswortel -print | xargs chgrp-temp

Xargs en vondst: complexe operaties

U kunt complexere bewerkingen uitvoeren met de opdrachten find en xargs. Zo kunt u bijvoorbeeld tijdelijke bestanden verwijderen die meer dan zeven dagen geleden zijn aangemaakt:

$ find /tmp -type f -naam "*" -mtime +7 -print0 | xargs -0 rm -f

En hier leest u hoe u processen die al meer dan zeven dagen actief zijn, met geweld kunt stoppen:

$ find /proc -user myuser -max Depth 1 -type d -mtime +7 -exec basisnaam() \; | xargs doden -9

Xargs en knippen

Xargs wordt vaak gebruikt in combinatie met het commando knippen, waarmee je lijnen kunt knippen tekstbestanden. Laten we er een paar bekijken praktische voorbeelden. Met behulp van de onderstaande opdracht wordt een lijst met alle gebruikers op het systeem op de console weergegeven:

$ knippen -d: -f1< /etc/passwd | sort | xargs echo

En het team kijkt

Bestand * | grep ASCII | knippen -d: -f1 | xargs -p vim
zal bestanden opeenvolgend openen voor bewerking in vim.
Laten we aandacht besteden aan de optie -p. Dankzij dit wordt de opdracht uitgevoerd in interactieve modus: Bevestiging (j/n) wordt gevraagd voordat elk bestand wordt geopend.

Kortom, hier is nog een complex en interessant voorbeeld— recursief zoeken naar de grootste bestanden in een bepaalde map:

$vind. -type f -printf "%20s %p\n" | sorteer -n | knippen -b22- | tr "\n" "\000" | xargs -0 ls -laSr

Parallelle werking van processen

Xargs wordt vaak gebruikt om meerdere processen parallel uit te voeren. Zo kunt u bijvoorbeeld meerdere mappen tegelijk comprimeren in tar.gz:

$ echo map1 map2 map3 | xargs -P 3 -I NAAM tar czf NAAM.tar.gz NAAM

In het onderstaande voorbeeld wordt de schakelaar -P gebruikt. Hij wijst maximale hoeveelheid processen die gelijktijdig zullen plaatsvinden. Laten we aannemen dat we 10 argumenten als invoer hebben. Als we het commando xargs invoeren met de schakeloptie -P 3, worden er 3 exemplaren van het commando dat volgt op xargs gestart, met elk van deze argumenten.

Met xargs kunt u ook meerdere bestanden parallel downloaden van internet:

In het gegeven voorbeeld met opgegeven adres alles wordt gedownload grafische bestanden Met jpg-extensie; De schakelaar -P geeft aan dat u 10 bestanden tegelijk moet downloaden.

Voorlopige resultaten

Laten we de voorlopige resultaten samenvatten en een paar regels formuleren voor het werken met xargs.

  1. Xargs werkt niet met bestanden die een spatie in de naam hebben. Om dit probleem met de opdracht xargs op te lossen, gebruikt u de optie −0. U kunt de spatie in de bestandsnaam ook als volgt omzeilen:
    $ xargs -I BESTAND mijn_opdracht “BESTAND”
  2. De opdracht xargs accepteert opdrachten van standaardinvoer, gescheiden door een spatie of nieuwe regel. Om deze opdrachten te groeperen, kunt u dubbel of gebruiken enkele aanhalingstekens. U kunt het scheidingsteken ook opgeven met de optie -d;
  3. Als er geen argumenten aan xargs worden doorgegeven, wordt het commando /bin/echo standaard uitgevoerd;
  4. In veel gevallen kan de opdracht xargs worden vervangen door een for-lus. Het commando bijvoorbeeld
    $vind. -type f -en -iname "*.deb" | xargs -n 1 dpkg -I
    volledig gelijk aan de cyclus
    $ voor bestand bij 'vinden'. -type f -en -iname "*.deb"`; doe dpkg -I "$bestand"; klaar

Niet-triviale voorbeelden

We hebben de basis onthouden typische opties gebruik overwogen... Laten we nu verder gaan met meer complexe en niet-triviale voorbeelden. Sommige hebben we zelf bedacht terwijl we aan alledaagse taken werkten, en andere hebben we van de site http://www.commandlinefu.com geleerd (we raden iedereen die de fijne kneepjes van het werken met de opdrachtregel wil leren ten zeerste aan bezoek het van tijd tot tijd - daar kun je soms heel veel vinden nuttige tips).

Ban IP-adressen uit de lijst

Om IP-adressen uit de lijst te weren, moet u ze toevoegen aan IP-tabellen met de DROP-regel. Deze bewerking wordt uitgevoerd met behulp van het commando:

$ cat bad_ip_list | xargs -I IP iptables -A INPUT -s IP -j DROP
U kunt ook een complexere bewerking uitvoeren en alle adressen verbannen via AS:

$ /usr/bin/whois -H -h whois.ripe.net -T route -i oorsprong AS<номер>|egrep "^route"|awk "(print $2)" |xargs -I NET iptables -A INPUT -s NET -j DROP

Het URL-formaat wijzigen

U kunt een URL zoals “http%3A%2F%2Fwww.google.com” converteren naar “www ,google.com” met behulp van de opdracht:

Echo "http%3A%2F%2Fwww.google.com" | sed -e"s/%\(\)/\\\\\x\1/g" | xargs echo -e

Een wachtwoord van 10 tekens genereren

Genereer sterk wachtwoord kan gedaan worden met een commando als:

$ tr -dc A-Za-z0-9_< /dev/urandom | head -c 10 | xargs

U kunt wachtwoorden genereren zonder de hulp van xargs: er is een gespecialiseerd hulpprogramma hiervoor, pwgen. Er worden ook enkele andere methoden voor het genereren van wachtwoorden beschreven.

Zoeken naar binaire bestanden die zijn geïnstalleerd zonder dpkg te gebruiken

Een dergelijke handeling kan nodig zijn als de machine bijvoorbeeld het slachtoffer is geworden van een hackeraanval en er kwaadaardige software op is geïnstalleerd. software. Het volgende commando helpt u te identificeren welke programma's de aanvallers hebben geïnstalleerd (het lijkt erop dat er “binaire bestanden” worden geïnstalleerd zonder gebruik te maken van de dpkg-pakketbeheerder):

$ cat /var/lib/dpkg/info/*.list > /tmp/listin ; ls /proc/*/exe |xargs -l leeslink | grep -xvFf /tmp/listin; rm /tmp/listin

Verouderde kernelpakketten verwijderen

$ dpkg -l linux-* | awk "/^ii/(print $2)" | grep -v -e `uname -r | knippen -f1,2 -d"-"` | grep -e | xargs sudo apt-get -y purge

Het probleem van het verwijderen van oude kernels is al besproken op Habré - zie (op dezelfde link kun je interessante voorbeelden van commando's vinden).

Het script converteren naar een string

Soms is het nodig om een ​​groot script in één regel om te zetten. Je kunt het als volgt doen:

  • selecteer
  • selecteer
  • Tags toevoegen

    Er is een heel vreemd commando in Linux xargs , waar goeroes dol op zijn, maar geen haast hebben om uit te leggen hoe het werkt. Het internet staat vol met recepten over ‘hoe je xargs moet gebruiken’, maar geen daarvan vermeldt duidelijk het allerbelangrijkste: wat dit commando eigenlijk doet.

    Het belangrijkste

    In algemene termen wordt overal hetzelfde geschreven: het xargs-commando neemt een invoerstroom (daarom wordt het altijd voorafgegaan door een commando en het stream-omleidingssymbool "|"), en voert met een magische syntaxis het commando uit dat daarin is gespecificeerd .

    Dit is wat het xargs-commando feitelijk doet.(Ik zal proberen het zo onpartijdig mogelijk te formuleren). Het breekt de stroom symbolen die erin worden gestuurd in stukken. Er worden scheidingstekens gebruikt om de stream te splitsen. En voor elk geselecteerd stuk voert het het commando uit dat aan de rechterkant is aangegeven, en vult dit commando aan de rechterkant aan met symbolen van het gevonden stuk.

    Ja, deze definitie gebruikt het concept ‘goed’ twee keer. De details worden hieronder uitgelegd. In de tussentijd is het beter om de structuur van het xargs-commando in de vorm van een afbeelding te bekijken. Syntactisch gezien bestaat het xargs-commando uit twee delen: links en rechts:

    Bovendien is er een ondubbelzinnige visuele scheiding tussen waar blijft en waar is rechterkant, gewoon nee. Als u de xargs-opdracht van iemand anders probeert te begrijpen, moet u deze "interface" zelf kunnen vinden. Hier zijn enkele voorbeelden:

    Volledige ploeg

    Linkerkant

    Rechterkant

    Opmerking

    xargs rm-rf

    xargs

    rm-rf

    xargs -0 rm -rf

    xargs-0

    rm-rf

    xargs -p -l gzip

    xargs -p -l

    gzip

    xargs tar -zcf pl.tar.gz

    xargs

    tar -zcf pl.tar.gz

    xargs-n2 fmv

    xargs-n2

    xargs -I-bestand mv

    xargs -I-bestand

    Ja, hier is geen sprake van een vergissing

    xargs chown-temp

    xargs

    chown-temp

    xargs doden -9

    xargs

    doden -9

    xargs -p vim

    xargs-p

    Dat wil zeggen, de regel is hier van toepassing: als er na xargs tekens staan ​​voorafgegaan door een minteken"-" , dan zijn dit opdrachtopties xargs . Zodra er symbolen zijn zonder minteken, dan zijn dit al symbolen aan de rechterkant. Maar je moet er rekening mee houden dat sommige opties xargs hebben na zichzelf nog enkele andere gegevens nodig die niet worden voorafgegaan door een minteken (zie voorbeeld met de optie-I ).

    En nu het allerbelangrijkste: welk commando voert het uit? xargs ? Waar duwt ze het pakket symbolen dat ze isoleert uit de invoerstroom? Het is simpel: ze plaatst deze symbolen rechts van het commando dat aan de rechterkant staat. Ik begrijp dat het concept ‘juist’ hier twee keer wordt gebruikt. Dan is hier een foto die alles op zijn plaats zet:

    Laten we nemen concreet voorbeeld. De map bevat de volgende bestanden:

    hoofd.cpp

    hoofd.h

    versie.cpp

    versie.h

    config.cpp

    configuratie.h

    data.cpp

    gegevens.h

    Binnen deze map wordt het commando uitgevoerd:

    $vind. -naam "*.cpp" | xargs -n 1 rm -rf

    Welke opdrachten genereert xargs? Om dit te beantwoorden, moet u begrijpen wat er aan de input zal worden voorgelegd. En de invoer zal het resultaat zijn van de find-opdracht:

    ./main.cpp

    ./versie.cpp

    ./config.cpp

    ./data.cpp

    De opdracht xargs houdt rekening met het scheidingsteken spatie, tab of regelinvoer (en hun continue reeksen). Er zullen dus uiteindelijk vier opdrachten worden uitgevoerd:

    rm -rf ./main.cpp

    rm -rf ./versie.cpp

    rm -rf ./config.cpp

    rm -rf ./data.cpp

    Erg belangrijke opmerking over de magische optie

    Er is één heel belangrijke opmerking. Als je het niet begrijpt, kun je niet goed met xargs werken, en word je als de auteurs van artikelen die denken te begrijpen hoe xargs werken, maar in feite vreselijke onzin schrijven. In het bovenstaande voorbeeld is de optie met een reden geschreven"-n1" .

    Optie "-n 1" zorgt ervoor dat xargs de opdracht uitvoert voor elk opeenvolgend deel van de invoerstroom. Ja, ik begrijp dat dit gek klinkt: het xargs-team zou tenslotte precies dat moeten doen! In de handleiding staat immers het volgende:"xargs leest items uit de standaardinvoer, begrensd door spaties (die kunnen worden beschermd met dubbele of enkele aanhalingstekens of een backslash) of nieuwe regels, en voert de opdracht uit (standaard is /bin/echo) een of meerdere keren met eventuele initiële argumenten gevolgd door items die worden gelezen uit standaardinvoer."Het probleem is dat dit standaard gebeurt als u dit niet opgeeft"-n 1" , behandelt xargs de gehele binnenkomende stroom, opgesplitst in spaties, tabs en regeleinden, als EEN argument. En in feite wordt de gehele binnenkomende stroom eenvoudigweg vervangen door de opdracht die wordt uitgevoerd. Wat een verrassing van de ontwikkelaars!

    Vraag: Hoe werken de voorbeelden die in artikelen worden gegeven, zoals

    $vind. -naam "*.cpp" | xargs rm-rf

    $vind. -naam "*.cpp" | xargs wc-l

    En ze werken simpelweg omdat de commando's zelf rm, wc en anderen zoals zij kunnen met een reeks bestandsnamen werken. En gebruikers denken ten onrechte dat dit zo is xargs Roept deze opdrachten meerdere keren aan voor elke bestandsnaam. En om hier zeker van te zijn, kunt u de optie gebruiken-T (druk de gegenereerde opdracht af xargs , voordat u het uitvoert). Maar om het resultaat te zien, moet u nog steeds de uitvoeromleidingsconstructie uit de foutenstroom gebruiken 2>&1 (omdat het gebruik van de optie-T geeft uitvoer naar een foutenstroom in plaats van naar de standaardconsole). En dit is wat je kunt zien.

    Als u de opdracht xargs schrijft zonder de optie "-n 1". , dan gebeurt het volgende:

    $vind. -naam "*.cpp" | xargs -t rm -rf 2>&1

    rm -rf ./main.cpp ./versie.cpp ./config.cpp ./data.cpp

    Het is duidelijk dat slechts één team zich vrijwillig heeft aangemeld rm , en er wordt een lijst met bestandsnamen aan doorgegeven. Het resultaat van zijn werk ziet er alleen uit alsof het voor elk bestand afzonderlijk is aangeroepen.

    Als u de optie gebruikt"-n 1" , dan zal het beeld anders zijn:

    $vind. -naam "*.cpp" | xargs-n 1 -t rm -rf 2>&1

    rm -rf ./main.cpp

    rm -rf ./versie.cpp

    rm -rf ./config.cpp

    rm -rf ./data.cpp

    Hier is het gedrag precies zoals beloofd. Onthoud deze optie en wees daar niet verbaasd over xargs werkt op de een of andere manier verkeerd als je deze optie niet gebruikt. Bedenk ook dat in veel artikelen op internet opdrachten met xargs gewoonweg onbruikbaar. De auteurs denken te weten wat het resultaat zou moeten zijn, en controleren niet eens het “voor de hand liggende”, waardoor een onvoorbereide gebruiker die besluit te herhalen wat er in het artikel staat, eigenlijk niets zal begrijpen.

    Er is nog een subtiel punt. xargs heeft een limiet voor de lengte van de invoerstroom. En als de invoerstroom te groot is, zal xargs deze in twee of meer stukken splitsen, en voor elk stuk zal het nog steeds een afzonderlijk commando aanroepen dat aan de rechterkant wordt aangegeven. Gebruik de optie om dergelijke onvoorziene situaties te voorkomen"-n1" .

    xargs-opdracht zonder argumenten

    Soms kom je een ontmoedigende constructie tegen zoals:

    tr -dc A-Za-z0-9_< /dev/urandom | head -c 10 | xargs

    Deze opdracht genereert willekeurig wachtwoord 10 tekens lang. Maar wat betekent commando? xargs geen argumenten aan het einde van deze opdracht?

    Het antwoord is eenvoudig. Team xargs denkt zonder argumenten eigenlijk dat het commando op zijn rechterkant staat/bin/echo . En geeft de binnenkomende stroom door via het commando echo . Waarom is dit nodig? IN in dit voorbeeld dit is eenvoudigweg om ervoor te zorgen dat het eindresultaat eindigt met een nieuwregelteken. Hier is een voorbeeld dat het verschil laat zien tussen een team dat dit niet heeft xargs is xargs:

    > tr -dc A-Za-z0-9_< /dev/urandom | head -c 10

    7jk2qx4cX8>

    > tr -dc A-Za-z0-9_< /dev/urandom | head -c 10 | xargs

    zSlr2HsbSa

    Spaties in bestandsnamen

    Omdat xargs spaties, tabs en nieuwe regels als scheidingstekens beschouwt, is er een probleem met het verwerken van bestandsnamen die witruimte tekens.

    Normaal gesproken worden de bestandsnamen voor de invoer van het xargs-programma geleverd op basis van het resultaat van de opdracht. vinden . En om dit probleem op te lossen het team find heeft een optie "-print0" . Het vervangt een regeleinde door een nulteken\x0 . En het xargs-commando heeft een optie "-0" (min nul), met behulp waarvan de invoerstroom wordt verdeeld in delen, gescheiden door het symbool\x0 .

    Stel dat er een bestand verschijnt in een map met de naam"nieuw bestand.cpp" . Als u de null-naar-null-conversieopties niet gebruikt, gebeurt het volgende:

    $vind. -naam "*.cpp" | xargs -n 1 -t rm -rf 2>&1

    rm -rf ./nieuw

    rm -rf-bestand.cpp

    en natuurlijk het bestand"nieuw bestand.cpp" wordt niet verwijderd. Als u de bovenstaande opties toevoegt, werkt de opdracht correct:

    $vind. -naam "*.cpp" -print0 | xargs -n 1 -t -0 rm -rf 2>&1

    rm -rf ./nieuw bestand.cpp

    en het bestand wordt verwijderd.

    Wat gebeurt er als u de optie "-n" niet schrijft?

    Houd er rekening mee dat de bovenstaande opdrachten de optie gebruiken"-n 1" . Wat gebeurt er als je het niet schrijft? In principe zal alles precies hetzelfde werken. Maar weinig mensen kunnen uitleggen hoe het werkt, omdat de commando's visueel hetzelfde zullen zijn, maar het resultaat zal anders zijn. Hier is een voorbeeld.

    Het commando zonder de optie "-n 1" en zonder de null-conversie-opties:

    $vind. -naam "*.cpp" | xargs -t rm -rf 2>&1

    "rm..." en het bestand wordt niet verwijderd"nieuw bestand.cpp" .

    En nu het commando zonder de optie "-n 1", maar met opties voor het converteren van het nulteken:

    $vind. -naam "*.cpp" -print0 | xargs -t -0 rm -rf 2>&1

    rm -rf ./main.cpp ./data.cpp ./config.cpp ./version.cpp ./nieuw bestand.cpp

    Als gevolg hiervan werd het team samengesteld"rm..." , uiterlijk absoluut identiek aan de vorige, maar het zal het bestand "new file.cpp" verwijderen!

    Het is moeilijk uit te leggen hoe dit werkt. De optie tenslotte"-0" is het xargs-commando, niet het rm-commando . Op de opdrachtmanpagina rm Er zijn geen aanwijzingen dat als bestandsnamen worden gescheiden door nultekens, witruimtetekens in bestandsnamen worden behandeld als letterlijke tekens in plaats van als scheidingstekens. Voor de auteur van het artikel blijft dit gedrag een mysterie en tot nu toe is er geen specialist gevonden die zou kunnen uitleggen wat er feitelijk gebeurt.

    De belangrijkste vraag

    Maar hoe construeer je commando's waarbij je niet alleen gevonden reeksen karakters aan de rechterkant hoeft toe te voegen? En als u na de waarde aan de rechterkant nog iets moet toevoegen? Wat moet ik doen? Maar absoluut niet! Dit is het antwoord. Het is niet mogelijk om een ​​willekeurig commando te construeren met behulp van xargs. Je kunt alleen een commando construeren dat bestaat uit een basisdeel (vast) en een rechterdeel (jokerteken). Dat is alles!

    Als xargs je toestond iets toe te voegen na het jokertekengedeelte, zou het leven met dit commando veel eenvoudiger zijn. Het zou bijvoorbeeld mogelijk zijn om aanhalingstekens voor en na het jokerteken te plaatsen, en er zouden eenvoudigweg geen problemen zijn met spaties in bestandsnamen. Maar de xargs-syntaxis staat dergelijk gedrag niet toe.

    Is het dus echt onmogelijk om in *NIX te construeren? het juiste commando? Natuurlijk is het mogelijk. Om dit te doen, kunt u de opdracht awk en de bijbehorende system()-functie gebruiken. Hoe u dit kunt doen, staat in het artikel: .