Recherche de site Web

Comment utiliser xargs pour construire des lignes de commande à partir d’une entrée standard


Même l’installation la plus basique de toute distribution Linux est livrée avec un ensemble d’utilitaires vraiment utiles : « xargs » est sans aucun doute l’un d’entre eux. En utilisant xargs, nous pouvons construire et exécuter des lignes de commande en utilisant des éléments de l’entrée standard comme arguments d’une commande. C’est particulièrement utile lorsqu’il s’agit de programmes qui ne lisent pas directement l’entrée standard.

Dans cet article, nous apprenons comment installer l’utilitaire xargs sur les distributions Linux les plus utilisées, et comment l’utiliser pour construire et exécuter des lignes de commande.

Dans ce tutoriel, vous allez apprendre :

  • Comment installer xargs sur les distributions Linux les plus utilisées
  • Comment utiliser xargs pour construire et exécuter des lignes de commande
  • Comment gérer les espaces dans les noms de fichiers
  • Comment faire en sorte que xargs demande une confirmation avant d’exécuter une commande
  • Comment exécuter plusieurs commandes sur chaque élément

Installation

L’utilitaire xargs est généralement distribué dans le paquet findutils, qui comprend un autre outil en ligne de commande très utile : « find « . Le paquet fait partie de l’installation la plus minimale de pratiquement toutes les distributions Linux, nous ne devrions donc pas avoir besoin de l’installer explicitement. Si, pour une raison étrange, cependant, il est absent de notre système, nous pouvons le récupérer en utilisant notre gestionnaire de paquets de distribution préféré.

Sur Debian et les distributions basées sur Debian, par exemple, nous pouvons utiliser apt :

sudo apt install findutils

Sur Fedora et d’autres distributions de la famille Red Hat, nous pouvons utiliser dnf, à la place :

sudo dnf install findutils

Le paquet est également disponible dans le dépôt « Core » d’Archilinux, et peut donc être installé à l’aide de pacman :

sudo pacman -S findutils

Voyons comment nous pouvons utiliser xargs pour construire et exécuter des lignes de commande.

Utilisation de xargs pour construire des lignes de commande

Que fait exactement l’utilitaire xargs ? Xargs utilise des éléments passés sur l’entrée standard, généralement en utilisant un opérateur de redirection de canal, comme arguments supplémentaires d’une commande que nous pouvons spécifier avec quelques arguments initiaux facultatifs. La syntaxe de xargs est assez facile à comprendre :

xargs [options] [command [initial-arguments]]

Voyons quelques exemples concrets d’utilisation de xargs.

Exemple 1 : Recherche de fichiers avec une extension spécifique contenant une chaîne de caractères

Un cas d’utilisation typique de xargs est lorsque nous devons rechercher une chaîne dans des fichiers avec une extension spécifique. Récemment, par exemple, j’ai voulu modifier un thème Wordpress, j’ai donc dû trouver dans quel fichier de modèle PHP se trouvait l’extrait de code que je voulais modifier. Voici comment j’ai utilisé xargs pour accomplir la tâche :

find theme -type f -name "*.php" | xargs grep -i "text-to-search"

Voyons ce que fait cette commande. Tout d’abord, nous avons utilisé find pour rechercher récursivement dans le répertoire du thème et nous avons demandé à l’utilitaire de rechercher les fichiers normaux (-type f) dont le nom se termine par « .php » (-name « *.php »), ensuite, nous avons redirigé la sortie standard de la commande vers xargs, de sorte que les fichiers qui correspondaient à la créteria ci-dessus aient été passés en argument à la commande grep.

À ce stade, vous pouvez penser : "l’utilitaire find a lui-même l’option -exec, qui exécute une commande donnée en utilisant les fichiers qui correspondent à la recherche comme arguments, pourquoi devrais-je utiliser xargs ? ”. La réponse est : « parce que xargs est plus rapide ». Jetons un coup d’œil à cet exemple. Supposons que nous voulions trouver tous les fichiers « .txt » dans le répertoire ~/.config contenant la chaîne « wizard ». Nous utilisons le temps pour obtenir la statistique de temps sur l’exécution de la commande. Nous utilisons d’abord -exec :

time find ~/.config -type f -name "*.txt" -exec grep -i "wizard" {} \;

Voici les résultats :

real    0m0.031s 
user    0m0.010s 
sys     0m0.020s

Maintenant, essayons avec xargs :

time find ~/.config -type f -name "*.txt" | xargs grep -i "wizard"

Cette fois, nous obtenons les statistiques suivantes :

real    0m0.015s 
user    0m0.006s 
sys     0m0.010s

Bien que le temps ne puisse pas être considéré comme un véritable outil de référence, en particulier pour les commandes de courte durée, il nous donne une idée générale de la commande la plus rapide. L’écart entre les deux commandes s’élargissait encore plus lors d’une recherche dans un plus grand ensemble de fichiers.

Exemple 2 : création d’une archive tarball contenant des fichiers potentiellement inexistants

Voici un autre cas dans lequel xargs pourrait être utile. Supposons que nous voulions créer une archive tar contenant certains fichiers, qui, cependant, peuvent ne pas exister. Si nous essayons d’inclure un fichier inexistant dans une archive tar, tar se termine avec un état d’échec :

tar -cpf archive.tar ~/nonexistingfile ~/.bashrc ~/.bash_profile
tar: Removing leading `/' from member names
tar: /home/doc/nonexistingfile: Cannot stat: No such file or directory
tar: Removing leading `/' from hard link targets
tar: Exiting with failure status due to previous errors

Une solution possible est de dire à tar d’ignorer les erreurs de lecture, en utilisant l’option --ignore-failed-read ; Cependant, ignorer les erreurs est rarement une bonne idée. Une meilleure solution est d’utiliser « find » pour rechercher les fichiers que nous voulons mettre dans l’archive :

find ~ -maxdepth 1 -type f \( -name .bashrc -o -name .bash_profile -o -name nonexistingfile \) | xargs tar -cpf archive.tar

Dans l’exemple ci-dessus, j’ai supposé que les fichiers étaient tous directement dans le répertoire personnel, j’ai donc utilisé l’option -maxdepth 1, qui désactive en fait la recherche récursive. J’ai également utilisé le filtre -type f, puis, j’ai inclus plusieurs filtres -name (un pour chaque fichier), séparés par l’opérateur -o, qui fonctionne comme un OU logique.

L’utilitaire « find » place un opérateur logique implicite ET (-a) entre des tests donnés, qui a une priorité plus élevée que OR. C’est pourquoi nous avons regroupé les tests « name » entre parenthèses (échappés pour éviter que le shell ne les interprète comme des caractères spéciaux). Si nous ne l’avions pas fait, l’expression aurait été équivalente à ce qui suit :

find ~ -maxdepth 1 -type f -a -name .bashrc -o -name .bash_profile -o -name nonexistingfile

En clair, cela aurait signifié : « trouver un fichier normal nommé « .bashrc », ou tout type de fichier nommé « .bash_profile », ou tout type de fichier nommé « nonexistingfile », dans le répertoire personnel, sans descendre dans les sous-répertoires.

En utilisant la stratégie, si un fichier n’existe pas, il n’est pas inclus dans la liste des fichiers à archiver.

Gestion des espaces dans les noms de fichiers

Il y a une chose que nous n’avons pas prise en compte dans les exemples précédents : les fichiers dont le nom contient des espaces. xargs, par défaut, utilise un caractère d’espace comme séparateur d’éléments, donc il sera confus si un fichier contient un espace dans son nom. En voici un exemple. Supposons qu’il existe un répertoire contenant trois fichiers, l’un d’entre eux incluant un espace dans son nom :

test
├── file1.txt
├── file2.txt
└── file 3.txt

Maintenant, supposons que nous voulions rechercher une chaîne dans l’un de ces fichiers, comme nous l’avons fait dans les exemples précédents :

find test -type f | xargs grep -i "content"

Comme prévu, la commande échouera :

grep: test/file: No such file or directory
grep: 3.txt: No such file or directory  

Vous voyez ce qui s’est passé ? Étant donné que le nom de « file 3.txt » contient un espace et que xargs utilise un espace comme délimiteur d’éléments, il a considéré « file » et « 3.txt » comme deux éléments distincts ! Nous pouvons résoudre ce problème en changeant le caractère utilisé par xargs comme délimiteur.

Lorsque nous combinons find et xargs, nous pouvons simplement utiliser l’ancienne option -print0 : cela fait en sorte que chaque élément trouvé soit suivi d’un caractère nul (la valeur par défaut est un saut de ligne). Du côté de xargs, à la place, nous pouvons passer l’option --null (ou -0), qui indique à l’utilitaire d’utiliser un caractère nul comme séparateur d’éléments, et de considérer les guillemets, les barres obliques inverses et la fin des chaînes de fichiers, littéralement :

find test -type f -print0 | xargs --null grep -i "content"

Comme alternative, nous pouvons utiliser l’option xargs -d, qui nous permet de spécifier le caractère que nous voulons utiliser comme délimiteur.

Faire en sorte que xargs demande une confirmation avant d’exécuter une commande

Dans certains cas, nous pouvons vouloir vérifier la commande qui serait exécutée par xargs. Dans ces cas, nous pouvons utiliser l’option -p ou --interactive. Appliquons-le à l’exemple précédent :

find test -type f -print0 | xargs --interactive --null grep -i "content"

Voici le résultat :

grep -i content test/file1.txt test/file2.txt 'test/file 3.txt'?...

La commande ne sera exécutée qu’après une réponse affirmative (en utilisant y ou Y). Si nous voulons seulement que la commande soit imprimée sur la sortie standard avant qu’elle ne soit réellement exécutée, à la place, nous pouvons utiliser l’option -t ou --verbose :

find test -type f -print0 | xargs --verbose --null grep -i "content"  
grep -i content test/file1.txt test/file2.txt 'test/file 3.txt'
test/file 3.txt:content

Exécution de plusieurs commandes sur chaque élément

Une option intéressante que nous pouvons utiliser avec xargs est -I, qui nous permet de créer une sorte de « modèle ». Il prend un « espace réservé » comme argument : chaque occurrence de l’espace réservé est remplacée au moment de l’exécution par des éléments lus à partir de l’entrée standard. À titre d’exemple trivial, supposons que nous voulions informer l’utilisateur que nous recherchons une chaîne dans un fichier, avant d’utiliser la commande grep. Nous courrions :

find test -type f | xargs -I % /bin/sh -c 'echo "searching in %"; grep -i "content" "%"'

Lorsque l’option -I est utilisée, le caractère « saut de ligne » (\n) est utilisé comme séparateur, donc, comme vous pouvez le voir, nous n’avons pas besoin d’utiliser --null, et nous pouvons simplement mettre entre guillemets l’espace réservé %.

Conclusions

Dans ce tutoriel, nous avons appris à utiliser l’utilitaire xargs pour construire et exécuter des lignes de commande à partir d’une entrée standard. L’utilitaire xargs est livré dans le paquet « findutils », avec un autre programme très utile : « find », et est souvent utilisé en conjonction avec lui, comme nous l’avons vu dans les exemples.

Articles connexes: