BASH traitement sur l'ensemble des arguments
gnugo
-
dubcek Messages postés 18789 Date d'inscription Statut Contributeur Dernière intervention -
dubcek Messages postés 18789 Date d'inscription Statut Contributeur Dernière intervention -
Bonjour,
et merci d'avance si vous pouvez me venir en aide!
J'ai besoin d'effectuer un traitement sur les arguments que je passe à un script bash.
J'ai donc à ma disposition 2 variables :
- $* qui est, si je ne me trompe pas, la concaténation de tous les arguments en un seul
GROS PROBLÈME : Si un de mes arguments contient un espace, impossible par la suite de le séparer correctement des autres ( ar1 "arg 2" arg3 => "arg1 arg 2 arg3" )
- $@ qui est, si je ne me trompe pas nom plus, une variable "spéciale" si laquelle on peut itérer avec une boucle for par exemple, et ainsi traiter un par un chaque argument ( arg, puis "arg 2", puis arg3 )
PROBLÈME : Ça ne me convient pas du tout, je ne souhaite pas itérer sur chaque argument, mais appliquer un traitement sur "l'ensemble de mes arguments", traitement incluant des espaces et des sauts de lignes.
Mes questions : Puis-je faire un traitement sur $@ sans faire boucle ? Comment sont séparés les arguments dans $@ ?
Merci
et merci d'avance si vous pouvez me venir en aide!
J'ai besoin d'effectuer un traitement sur les arguments que je passe à un script bash.
J'ai donc à ma disposition 2 variables :
- $* qui est, si je ne me trompe pas, la concaténation de tous les arguments en un seul
GROS PROBLÈME : Si un de mes arguments contient un espace, impossible par la suite de le séparer correctement des autres ( ar1 "arg 2" arg3 => "arg1 arg 2 arg3" )
- $@ qui est, si je ne me trompe pas nom plus, une variable "spéciale" si laquelle on peut itérer avec une boucle for par exemple, et ainsi traiter un par un chaque argument ( arg, puis "arg 2", puis arg3 )
PROBLÈME : Ça ne me convient pas du tout, je ne souhaite pas itérer sur chaque argument, mais appliquer un traitement sur "l'ensemble de mes arguments", traitement incluant des espaces et des sauts de lignes.
Mes questions : Puis-je faire un traitement sur $@ sans faire boucle ? Comment sont séparés les arguments dans $@ ?
Merci
A voir également:
- Arguments bash
- Bingo bash - Télécharger - Divers Jeux
- Bash list ✓ - Forum Shell
- Bash permission non accordée - Forum Shell
- Bash pause ✓ - Forum Shell
- Bash addition - Forum Programmation
16 réponses
hello
en changeant IFS et avec des ", on peut avoir un autre caractère qu'espace comme séparateur
en changeant IFS et avec des ", on peut avoir un autre caractère qu'espace comme séparateur
$ set "a 1" "b 2" "c 3" $ echo $* a 1 b 2 c 3 $ echo "$*" a 1 b 2 c 3 $ IFS=";" $ echo "$*" a 1;b 2;c 3 $
Merci,
ça répond vraiment bien à ce que je cherche, je peux alors travailler avec $* sans soucis, mais...
maintenant il me faut trouver bon séparateur.
Mes paramètres sont des noms de fichiers, pourrais-tu me dire s'il y a un caractère ne pouvant pas faire parti des noms de fichiers, que je pourrais utiliser ?
ça répond vraiment bien à ce que je cherche, je peux alors travailler avec $* sans soucis, mais...
maintenant il me faut trouver bon séparateur.
Mes paramètres sont des noms de fichiers, pourrais-tu me dire s'il y a un caractère ne pouvant pas faire parti des noms de fichiers, que je pourrais utiliser ?
tout les caractères sont autorisés dans les noms, mais je dirais:
; puisque c'est un séparateur de commande, # commentaires, etc
; puisque c'est un séparateur de commande, # commentaires, etc
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Oui mais si j'ai un fichier avec un de ces caractères qui sont autorisés, ça ne marchera pas
Ce serait une faille dans mon script que de faire un truc pareil.
Du coup je ne vois pas comment faire... à part en me débrouillant en itérant dans une boucle pour reconstruire ma variable, mais c'est justement pour éviter de faire ça que je suis venu chercher de l'aide.
$@ arrive bien à les séparer pourtant, il fait comment lui ?
Ce serait une faille dans mon script que de faire un truc pareil.
Du coup je ne vois pas comment faire... à part en me débrouillant en itérant dans une boucle pour reconstruire ma variable, mais c'est justement pour éviter de faire ça que je suis venu chercher de l'aide.
$@ arrive bien à les séparer pourtant, il fait comment lui ?
Salut,
je ne souhaite pas itérer sur chaque argument, mais appliquer un traitement sur "l'ensemble de mes arguments", traitement incluant des espaces et des sauts de lignes.
Pour aller plus vite et gagner du temps :
Quels traitements comptes-tu faire ?
De quelles façons ?
je ne souhaite pas itérer sur chaque argument, mais appliquer un traitement sur "l'ensemble de mes arguments", traitement incluant des espaces et des sauts de lignes.
Pour aller plus vite et gagner du temps :
Quels traitements comptes-tu faire ?
De quelles façons ?
$@ affiche l'ensemble des $1, $2, etc
tester si le caractère est présent dans $*, si oui en prendre un autre
tester si le caractère est présent dans $*, si oui en prendre un autre
$ set "a 1" "b 2" "c;3" $ $ echo "$*" a 1 b 2 c;3 $ $ grep -q ";" <<<"$*" $ echo $? 0 $ $ IFS="#" # on utilise # et pas ; $ $ echo "$*" a 1#b 2#c;3 $ $
-->Réponse à zipe31 :
Bah en fait peu importe le traitement, je sais que je pourrai éventuellement le faire avec une boucle mais ce n'est pas cette solution que je cherche, même si elle fonctionnerait parfaitement.
Pour simplifier au maximum, disons que j'ai en arguments des noms de fichiers
Et je souhaite en faire une liste dans une seule variable qui contiendra alors tous mes noms de fichiers séparés par un caractère.
Ensuite, je passe cette liste à un programme exécutable qui lui effectuera le traitement.
Mais je ne trouve pas comment séparer mes noms de fichiers puisque tous les caractères peuvent être utilisés.
Pourtant je constate que dans $@ ils semblent correctement séparés, donc ça doit être possible.
J'espère être suffisamment clair. N'hésitez pas à me poser des questions si ça ne l'est pas.
Et encore merci
-->À ducek :
Intéressant mais si dans mes arguments j'ai tous les caractères possibles de noms de fichiers, ce qui est possible, le script ne peut plus rien faire,non?
Cette façon de faire à l'air en plus très compliquée, tester tous les caractères possibles pour en trouver un de libre...ça fait beaucoup
En mettant directement Le séparateur qu'il faut (celui de $@ peut être?) ça sera quand même beaucoup plus simple et efficace
Bah en fait peu importe le traitement, je sais que je pourrai éventuellement le faire avec une boucle mais ce n'est pas cette solution que je cherche, même si elle fonctionnerait parfaitement.
Pour simplifier au maximum, disons que j'ai en arguments des noms de fichiers
Et je souhaite en faire une liste dans une seule variable qui contiendra alors tous mes noms de fichiers séparés par un caractère.
Ensuite, je passe cette liste à un programme exécutable qui lui effectuera le traitement.
Mais je ne trouve pas comment séparer mes noms de fichiers puisque tous les caractères peuvent être utilisés.
Pourtant je constate que dans $@ ils semblent correctement séparés, donc ça doit être possible.
J'espère être suffisamment clair. N'hésitez pas à me poser des questions si ça ne l'est pas.
Et encore merci
-->À ducek :
Intéressant mais si dans mes arguments j'ai tous les caractères possibles de noms de fichiers, ce qui est possible, le script ne peut plus rien faire,non?
Cette façon de faire à l'air en plus très compliquée, tester tous les caractères possibles pour en trouver un de libre...ça fait beaucoup
En mettant directement Le séparateur qu'il faut (celui de $@ peut être?) ça sera quand même beaucoup plus simple et efficace
Rebonsoir,
Alors j'ai un peu creusé là dessus et mon traitement fonctionne parfaitement si je sépare mes fichiers par le caractère NUL ( '\0' )
J'ai pu faire les tests grâce à l'option -print0 de find qui me sépare bien les fichiers avec un '\0'
Maintenant il faut juste que je fasse la même chose sans find
Comment mettre sur la sortie de mon script la liste de ses arguments séparés par ce caractère ?
En effet, je dois passer cette liste à l'entrée standard de mon programme de traitement
J'ai essayé des choses comme : ./traitement <<<"$@" mais pas concluant
(Je suis ouvert à toute suggestion cette fois :] )
Alors j'ai un peu creusé là dessus et mon traitement fonctionne parfaitement si je sépare mes fichiers par le caractère NUL ( '\0' )
J'ai pu faire les tests grâce à l'option -print0 de find qui me sépare bien les fichiers avec un '\0'
Maintenant il faut juste que je fasse la même chose sans find
Comment mettre sur la sortie de mon script la liste de ses arguments séparés par ce caractère ?
En effet, je dois passer cette liste à l'entrée standard de mon programme de traitement
J'ai essayé des choses comme : ./traitement <<<"$@" mais pas concluant
(Je suis ouvert à toute suggestion cette fois :] )
Je veux bien faire une boucle si au final j'obtiens ma liste
Quelque chose comme
Conviendrait parfaitement.
Et find ne convient pas car je ne souhaite traiter qu'une liste de fichiers précis.
./script fic1 file5 "aaa bb" | traitement
find recherche des fichiers. dans mon cas je connais déjà les fichiers que je veux traiter. Find peut prendre ma liste et me la renvoyer au bon format avec print0 ?
Quelque chose comme
for f in "$@" do liste="$liste\0$f" done
Conviendrait parfaitement.
Et find ne convient pas car je ne souhaite traiter qu'une liste de fichiers précis.
./script fic1 file5 "aaa bb" | traitement
find recherche des fichiers. dans mon cas je connais déjà les fichiers que je veux traiter. Find peut prendre ma liste et me la renvoyer au bon format avec print0 ?
Bon alors pour l'instant j'ai fait ça :
for f in "$@"
do
echo -n "$f"
echo -ne "\0"
done | traitement
Ça marche, mais c'est pas terrible je trouve, surtout quand on pense que "$@" est déjà au bon format.
Voilà. Qu'en pensez-vous? Comment auriez-vous fait ?
for f in "$@"
do
echo -n "$f"
echo -ne "\0"
done | traitement
Ça marche, mais c'est pas terrible je trouve, surtout quand on pense que "$@" est déjà au bon format.
Voilà. Qu'en pensez-vous? Comment auriez-vous fait ?
ah, j'ai oublié : pourquoi «./traitement <<<"$@" [...] pas concluant » ?
$ premiere() { deuxieme "$@";} $ deuxieme() { printf '%s\n' "$@";} $ premiere foo bar "bar baz" foo bar bar bazlà, c'est des fonctions, mais ce serait pareil avec des scripts.
Non c'est justement ce qu'il faisait au départ.
Mais parfois le traitement est amené a travailler sur un grand nombre de fichiers, Et quand il y a trop de noms j'ai une erreur "argument line too long"
Voilà pourquoi je cherche maintenant à faire passer cette liste sur l'entrée standard. Comme ça , pas de limite, plus de problème
Mais parfois le traitement est amené a travailler sur un grand nombre de fichiers, Et quand il y a trop de noms j'ai une erreur "argument line too long"
Voilà pourquoi je cherche maintenant à faire passer cette liste sur l'entrée standard. Comme ça , pas de limite, plus de problème
Bah je vois pas ou est le problème je pense avoir donné tous les détails
Je n'ai plus le script ni le prog de traitement sous les yeux
Si vous voulez tester le même comportement:
#Version avec lecture de l'entrée standard
for f in "$@"
do
echo -n "$f"
echo -ne "\0"
done | ssh 127.0.0.1 cat
#Version utilisant les paramètres
ssh 127.0.0.1 "echo \"$@\""
Les 2 fonctionnent mais... faites le test avec 4000 noms de fichiers dans "$@" , vous verrez une belle erreur too many arguments
Si vous avez une solution pour éviter le pb tout en conservant le fonctionnement par arguments, je suis ouvert
Mais à mon avis avec une liste de fichiers pouvant atteindre une grosse taille, un traitement par flux dans l'entrée standard c'est mieux que la ligne de commande limitée
Je n'ai plus le script ni le prog de traitement sous les yeux
Si vous voulez tester le même comportement:
#Version avec lecture de l'entrée standard
for f in "$@"
do
echo -n "$f"
echo -ne "\0"
done | ssh 127.0.0.1 cat
#Version utilisant les paramètres
ssh 127.0.0.1 "echo \"$@\""
Les 2 fonctionnent mais... faites le test avec 4000 noms de fichiers dans "$@" , vous verrez une belle erreur too many arguments
Si vous avez une solution pour éviter le pb tout en conservant le fonctionnement par arguments, je suis ouvert
Mais à mon avis avec une liste de fichiers pouvant atteindre une grosse taille, un traitement par flux dans l'entrée standard c'est mieux que la ligne de commande limitée
J'ai une autre interrogation sur le même sujet :
Est-il possible de récupérer avec la commande ls une liste de fichiers pour la traiter en arguments ?
C'est à dire : "./script $(ls)" pour obtenir la liste des fichiers dans la liste des arguments "$@" du script.
Ça ne marche pas avec un fichier contenant un espace, il pense qu'il y a 2 fichiers. "aa bb" donne "aa" et "bb" dans "$@"
En faisant ./script "$(ls)" c'est pire, il considère toute la liste de fichiers comme un seul
Est-il possible de récupérer avec la commande ls une liste de fichiers pour la traiter en arguments ?
C'est à dire : "./script $(ls)" pour obtenir la liste des fichiers dans la liste des arguments "$@" du script.
Ça ne marche pas avec un fichier contenant un espace, il pense qu'il y a 2 fichiers. "aa bb" donne "aa" et "bb" dans "$@"
En faisant ./script "$(ls)" c'est pire, il considère toute la liste de fichiers comme un seul
Effectivement le IFS=$'\n' ; peut être une bonne solution mais il le problème c'est qu'il faudra le taper à chaque fois, on ne peut pas l'automatiser ou le mettre dans le script car la "transformation" du retour du 'ls' et même le ls lui même qui renvoie un mauvais résultat(\n séparateur) se fait en amont. (ls sépare par des \n alors que c'est un caractère possible pour les noms de fichiers...dommage). Donc soit je l'utilise et je fais avec son résultat sachant à quoi m'en tenir, soit je ne l'utilise pas.
En tout cas mon souci premier est résolu et je vous remercie pour votre aide !
Merci
En tout cas mon souci premier est résolu et je vous remercie pour votre aide !
Merci