J'utilise Bash 4.3.48(1) dans Ubuntu 16.04 (xenial) avec une pile LEMP.
J'essaie de créer un php.ini
remplace le fichier de manière indépendante de la version avec printf
.
1) L'opération indépendante de la version échoue :
printf "[PHP]n post_max_size = 200Mn upload_max_filesize = 200Mn cgi.fix_pathinfo = 0" > /etc/php/*/fpm/zz_overrides.ini
L'erreur suivante est donnée :
bash :/etc/php/*/zz_overrides.ini :aucun fichier ou répertoire de ce type
2) L'opération de gnostic de version réussit :
printf "[PHP]n post_max_size = 200Mn upload_max_filesize = 200Mn cgi.fix_pathinfo = 0" > /etc/php/7.0/fpm/zz_overrides.ini
Comme vous pouvez le voir, les deux sont fondamentalement identiques à part *
vs 7.0
.
- Je n'ai trouvé aucune idée de ce problème (regex ?) dans
man printf
. - J'ai cherché sur Google et je n'ai rien trouvé sur "autoriser regex dans printf".
Pourquoi l'opération indépendante de la version échoue-t-elle et existe-t-il un contournement ?
Edit :Si possible, il est très important pour moi d'utiliser une opération sur une seule ligne.
Réponse acceptée :
Le comportement d'une correspondance de modèle dans une redirection semble différer entre les shells. Parmi ceux de mon système, dash et ksh93 ne développent pas le modèle, vous obtenez donc un nom de fichier avec un *
littéral . Bash le développe, mais uniquement si le modèle correspond à un fichier. Il se plaint s'il y a plus de noms de fichiers qui correspondent. Zsh fonctionne comme si vous donniez plusieurs redirections, il redirige la sortie vers tous fichiers correspondants.
(1) sauf lorsqu'il est non interactif et en mode POSIX
Si vous voulez que la sortie aille dans tous les fichiers correspondants, vous pouvez utiliser tee
:
echo ... | tee /path/*/file > /dev/null
Si vous voulez qu'il aille dans un seul fichier, le problème est de décider lequel utiliser. Si vous voulez vérifier qu'il n'y a qu'un seul fichier qui correspond au modèle, développez toute la liste et comptez-les.
En bash/ksh :
names=(/path/*/file)
if [ "${#names[@]}" -gt 1 ] ; then
echo "there's more than one"
else
echo "there's only one: ${names[0]}"
fi
Dans le shell standard, set
les paramètres positionnels et utilisez $#
pour le décompte.
Bien sûr, si le modèle ne correspond à aucun fichier, il est laissé tel quel, et puisque le glob est au milieu, le résultat pointe vers un répertoire inexistant. C'est la même chose que d'essayer de créer /path/to/file
, avant /path/to
existe, c'est juste ici que nous avons /path/*
à la place, littéralement, avec l'astérisque.
Pour faire face à cela, vous devez développer le ou les noms de répertoires sans le nom de fichier, puis ajouter le nom de fichier à tous les répertoires. C'est un peu moche…
dirs=(/path/*)
files=( "${dirs[@]/%//file}" )
puis nous pouvons utiliser ce tableau :
echo ... | tee "${files[@]}" > /dev/null
Ou nous pourrions choisir la solution de facilité et boucler sur le modèle de nom de fichier. C'est un peu insatisfaisant dans le cas le plus général, car cela nécessite d'exécuter la commande principale une fois pour chaque fichier de sortie, ou d'utiliser un fichier temporaire pour conserver la sortie.
for dir in /path/* ; do
echo ... > "$dir/file"
done