GNU/Linux >> Tutoriels Linux >  >> Linux

La redirection vers un nom de fichier global échoue ?

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 

Linux
  1. Pipes et redirection sous Linux - expliqués !

  2. Comprendre le fichier /etc/hosts sous Linux

  3. wget :nom du fichier téléchargé

  4. Gestion des noms de fichiers multiplateformes dans .NET Core

  5. Comment supprimer un fichier avec un nom bizarre ?

La redirection bash expliquée avec des exemples

Créer un fichier vide ayant un nom de variable dans un script ?

Shell Scripting Part4 - Entrée, sortie et redirection

Comment connaître le nom du fichier de script dans un script Bash ?

Supprimer un lien symbolique vers un répertoire

mkdir -p échoue lorsque le répertoire existe