Effektiv bruk av Linux-kommandoer med xargs
Har du behov for å kombinere flere Linux-kommandoer, men støter på at noen av dem ikke aksepterer input via rør? Da kan `xargs` være løsningen. Dette verktøyet tar utdata fra en kommando og sender det videre som parametere til en annen.
I Linux har alle standardverktøy tilknyttet seg tre datastrømmer. Disse er standard input-strøm (stdin), standard output-strøm (stdout), og standard feilstrøm (stderr). Disse strømmene håndterer tekst. Vi gir input (stdin) til en kommando gjennom tekst, og svaret (stdout) skrives også som tekst til terminalen. Eventuelle feilmeldinger (stderr) vises også i terminalvinduet som tekst.
En av de unike egenskapene ved Linux og Unix-lignende operativsystemer er evnen til å overføre stdout-utdata fra en kommando som stdin-input til en annen. Den første kommandoen bryr seg ikke om at utdataene ikke sendes til et terminalvindu, og den andre kommandoen tar ikke hensyn til hvorvidt input kommer fra tastaturet eller ikke.
Selv om alle Linux-kommandoer har disse tre standardstrømmene, er det ikke alle som godtar stdout fra en annen kommando som input til sin stdin. Dette betyr at du ikke alltid kan sende data som input til disse kommandoene.
`xargs` er en kommando designet for å skape utførelsespipelines ved hjelp av standard datastrømmer. Ved å bruke `xargs` kan vi få kommandoer som `echo`, `rm` og `mkdir` til å akseptere standard input som argumenter.
Forstå `xargs`-kommandoen
`xargs` aksepterer input fra rørledninger, men kan også lese input fra en fil. `xargs` bruker denne inputen som parametere for kommandoene vi ber den om å arbeide med. Hvis vi ikke spesifiserer en kommando, bruker `xargs` som standard kommandoen `echo`.
Vi kan demonstrere hvordan `xargs` alltid genererer en enkelt utdatalinje, selv med input som strekker seg over flere linjer.
Ved å bruke `-1` (en fil per linje) med `ls`, får vi en enkel kolonne med filnavn.
ls -1 ./*.sh
Dette viser alle shell-skriptfilene i gjeldende mappe.
Vi får en enkel kolonne som forventet. Hva skjer hvis vi sender dette gjennom `xargs`?
ls -1 ./*.sh | xargs
Utdatene skrives til terminalvinduet, som en enkel, lang tekststreng.
Det er denne evnen som gjør at vi kan bruke `xargs` til å sende parametere inn i andre kommandoer.
Bruk av `xargs` med `wc`
Vi kan bruke `xargs` til enkelt å telle ord, tegn og linjer i flere filer.
ls *.page | xargs wc
Slik fungerer dette:
`ls` viser alle filer med filendelsen `.page` og sender listen til `xargs`.
`xargs` sender filnavnene til `wc`.
`wc` behandler filnavnene som om den hadde mottatt dem som kommandolinjeparametere.
Statistikken for hver fil vises, sammen med en totalsum.
Interaktiv bruk av `xargs` med bekreftelse
Ved å bruke `-p` (interaktiv) kan vi la `xargs` spørre om bekreftelse før kommandoen utføres.
Hvis vi sender en streng med filnavn til `touch` gjennom `xargs`, vil `touch` opprette de spesifiserte filene.
echo 'one two three' | xargs -p touch
Kommandoen som skal utføres vises, og `xargs` venter på svar. Du kan skrive `y` eller `Y` for å fortsette, eller `n` eller `N` for å avbryte. Deretter trykker du enter.
Hvis du bare trykker enter, tolkes dette som `n`. Kommandoen utføres kun dersom du skriver `y` eller `Y`.
Vi tastet `y` og trykket enter. Vi kan bruke `ls` for å sjekke om filene er opprettet.
ls one two three
Bruk av `xargs` med flere kommandoer
Vi kan bruke flere kommandoer med `xargs` ved å bruke `-I` (innledende argumenter). Dette alternativet definerer en «erstatt-streng.» Uansett hvor erstatningsstrengen vises på kommandolinjen, settes verdiene som er levert til `xargs` inn.
La oss bruke `tree`-kommandoen til å se undermapper fra gjeldende mappe. Alternativet `-d` (directory) får `tree` til å ignorere filer og kun rapportere om mapper.
tree -d
Det finnes en undermappe kalt `bilder`.
I en fil kalt `directories.txt` har vi navnene på noen mapper vi ønsker å opprette. Vi kan se innholdet med `cat`.
cat directories.txt
Vi skal bruke dette som input for `xargs`. Kommandoen vi skal bruke er denne:
cat directories.txt | xargs -I % sh -c 'echo %; mkdir %'
Dette kan deles opp slik:
`cat directories.txt |`: Dette sender innholdet i `directories.txt` (alle de nye mappenavnene) til `xargs`.
`xargs -I %`: Dette definerer en «erstatt-streng» med tokenet `%`.
`sh -c`: Dette starter et nytt subshell. `-c` (kommando) forteller skallet å lese kommandoer fra kommandolinjen.
`’echo %; mkdir %’`: Hvert `%`-token vil erstattes med mappenavnene som sendes av `xargs`. `echo`-kommandoen vil skrive ut mappenavnet, og `mkdir`-kommandoen vil opprette mappen.
Mappene listes opp en etter en.
Vi kan bruke `tree` igjen for å bekrefte at mappene er opprettet.
tree -d
Kopiere filer til flere steder
Vi kan bruke `xargs` for å kopiere filer til flere steder med en enkelt kommando.
Vi sender navnene på to mapper til `xargs` som input-parametre. Vi ber `xargs` sende en av parameterne av gangen til kommandoen den jobber med.
I dette tilfellet er kommandoen `cp`. Effekten blir å kalle `cp` to ganger, hver gang med en av de to mappene som kommandolinjeparameter. Xargs-parameteren som gjør dette mulig er `-n` (maks antall). Vi setter denne til 1.
Vi bruker også `-v` (verbose) med `cp`, slik at den rapporterer hva som skjer.
echo ~/Backups/ ~/Documents/page-files/ | xargs -n 1 cp -v ./*.page
Filene kopieres til de to mappene, en om gangen. `cp` rapporterer hver filkopieringshandling, slik at vi kan se dem skje.
Slette filer i nestede mapper
Dersom filnavn inneholder mellomrom og spesielle tegn som for eksempel linjeskift, vil ikke `xargs` kunne tolke dem korrekt. Dette løser vi ved å bruke `-0` (nullterminator). Dette forteller `xargs` at null-tegnet skal brukes som siste skilletegn for filnavn.
Vi bruker `find` i dette eksemplet. `find` har sin egen måte for å håndtere mellomrom og spesielle tegn i filnavn. Det er alternativet `-print0` (fullt navn, nulltegn).
find . -name "*.png" -type f -print0 | xargs -0 rm -v -rf "{}"
Dette kan deles opp slik:
`find . -name «*.png»`: `find` søker fra gjeldende mappe `.` etter objekter som har navn som passer med `*.png` og som er filer (`-type f`).
`-print0`: Navn avsluttes med null-tegn, og mellomrom og spesielle tegn blir håndtert.
`xargs -0`: `xargs` vurderer filnavn som nullterminerte, slik at mellomrom og spesielle tegn ikke skaper problemer.
`rm -v -rf «{}»`: `rm` gir detaljert rapport (-v). Den vil være rekursiv (-r) og se gjennom nestede undermapper, og vil fjerne filer uten å spørre (-f). «{}» erstattes med hvert filnavn.
Alle undermapper blir gjennomsøkt, og filer som passer med søkemønsteret blir slettet.
Fjerne nestede mapper
La oss si at vi ønsker å fjerne et sett med nestede undermapper. Vi kan se dem med `tree`.
tree -d
find . -name "level_one" -type d printo | xargs -o rm -v -rf "{}"
Denne kommandoen bruker `find` til å søke rekursivt i gjeldende mappe. Søkemålet er en mappe som heter `level_one`. Mappenavnene sendes via `xargs` til `rm`.
De eneste vesentlige endringene mellom denne og forrige kommando er at søkeordet er navnet på den øverste mappen og `-type d` forteller `find` at den skal lete etter mapper, ikke filer.
Navnet på hver mappe skrives ut etterhvert som den fjernes. Vi kan sjekke med `tree`.
tree -d
Alle de nestede undermappene er slettet.
Slette alle filer, bortsett fra en bestemt filtype
Vi kan bruke `find`, `xargs` og `rm` for å slette alle filer bortsett fra en filtype vi ønsker å beholde. Dette virker litt motintuitivt, men vi oppgir navnet på filtypen vi ønsker å beholde, ikke de vi ønsker å slette.
Alternativet `-not` ber `find` returnere navnene på filer som ikke passer med søkemønsteret. Vi bruker alternativet `-I` (innledende argumenter) med `xargs` igjen. Denne gangen er «erstatningsstreng»-tokenet vi definerer `»{}»`. Dette vil fungere på nøyaktig samme måte som «erstatningsstreng»-tokenet vi brukte tidligere, som var `%`.
find . -type f -not - name "*.sh" -print0 | xargs -0 -I {} rm -v {}
Vi kan sjekke med `ls`. De eneste filene som er igjen i mappen, er de som passer med søkemønsteret `*.sh`.
ls -l
Opprette en arkivfil med `xargs`
Vi kan bruke `find` for å søke etter filer og sende dem via `xargs` til `tar` for å lage en arkivfil.
Vi skal søke i gjeldende mappe. Søkemønsteret er `*.page`, så vi skal lete etter filer som ender på `.page`.
find ./ - name "*.page" -type f -print0 | xargs -0 -tar -cvzf page_files.tar.gz
Filene listes opp etterhvert som arkivfilen opprettes.
Dataformidleren
Noen ganger trenger man et verktøy for å koble ting sammen. `xargs` bygger bro mellom kommandoer som kan produsere informasjon og kommandoer som ikke er bygget for å akseptere den.
Både `xargs` og `find` har et stort antall alternativer. Vi oppfordrer deg til å sjekke deres man-sider for å lære mer.