Bash cité de la matrice de l'expansion
Quand j'écris un bash programme que j'ai généralement de construire des appels comme suit:
declare -a mycmd=( command.ext "arg1 with space" arg2 thing etc )
"${mycmd[@]}" || echo "Failed: foo"
Où die foo
est un bash fonction qui imprime Error foo
et les sorties.
Mais si je veux être clair sur l'erreur de la raison, je veux imprimer la commande a échoué:
"${mycmd[@]}" || echo "Failed: foo: ${mycmd[*]}"
De sorte que l'utilisateur peut exécuter la mort de commande et de trouver pourquoi. Toutefois, la citation est perdu sur ce passe - le message d'Échec, les arguments contenant des espaces ou des caractères d'échappement ne sont pas imprimés dans une manière qui peut être cut-n-collé et de l'exécuter.
Quelqu'un aurait-il une suggestion pour un compact moyen de corriger ce problème?
Je pense que le problème est la façon dont bash traite avec l'argument d'analyse pour les commandes, et la manière (builtin) echo traite les arguments. Une autre façon de poser le problème est:
Comment puis-je impression les guillemets autour des arguments avec des espaces dans le bash suivant l'exemple (qui doit être exécuté comme un script, pas en mode immédiat):
#!/bin/bash
mkdir qatest; cd qatest
declare -a myargs=(1 2 "3 4")
touch "${myargs[@]}"
ls
echo "${myargs[@]}"
résultat réel:
1 2 3 4
1 2 3 4
résultat souhaité
1 2 3 4
1 2 "3 4"
OU
1 2 3 4
"1" "2" "3 4"
Dans quelques bash caractères de code.
Question fermée: @camh répondu magnifiquement:
script de mise à jour:
#!/bin/bash
mkdir qatest; cd qatest
declare -a myargs=(1 2 "3 4")
touch "${myargs[@]}"
ls
echo "${myargs[@]}"
echo $(printf "'%s' " "${myargs[@]}")
de sortie:
1 2 3 4
1 2 3 4
'1' '2' '3 4'
OriginalL'auteur Alex Brown | 2012-10-20
Vous devez vous connecter pour publier un commentaire.
Votre problème est avec
echo
. Il est d'obtenir le bon nombre de paramètres, avec certains paramètres contenant des espaces, mais elle est sortie perd la distinction des espaces entre les paramètres et les espaces à l'intérieur de paramètres.Au lieu de cela, vous pouvez utiliser
printf(1)
de sortie les paramètres et toujours inclure les guillemets, par l'utilisation de printf est la caractéristique qui s'applique à la chaîne de format successivement à des paramètres lorsqu'il y a plus de paramètres que les spécificateurs de format dans la chaîne de format:Qu'il va mettre des guillemets simples autour de chaque argument, même s'il n'est pas nécessaire:
J'ai utilisé des guillemets simples pour s'assurer que d'autres shell métacaractères ne sont pas manipulés correctement. Cela fonctionne pour tous les caractères sauf le devis lui-même - c'est à dire si vous avez un paramètre contenant une apostrophe, la sortie de la commande ci-dessus va pas les couper et les coller correctement. C'est probablement le plus proche, vous obtiendrez sans se salir.
Edit: Presque 5 ans plus tard et depuis que j'ai répondu à cette question, bash 4.4 a été libéré. Cela a
"${var@Q}"
expansion qui cite la variable telle qu'elle peut être analysée en arrière par bash.Cela simplifie cette réponse à:
Cela permettra de gérer correctement les guillemets simples dans un argument, qui a mon ancienne version n'a pas.
OriginalL'auteur camh
bash printf commande a un %q format qui ajoute approprié de citations pour les chaînes comme ils sont imprimés:
Vous l'esprit, de son idée de la "meilleure" façon de citer quelque chose, n'est-ce pas toujours le même que le mien, par exemple, il a tendance à préférer s'échapper de drôles de caractères au lieu d'emballage de la chaîne de caractères entre guillemets. Par exemple:
Imprime:
OriginalL'auteur Gordon Davisson
Comment sur
declare -p quotedarray
?-- edit --
Acctually,
declare -p quotedarray
saura vous satisfaire but. Si vous insistez sur le format de sortie de la suite, alors j'ai une petite astuce serait de faire le travail, mais juste pour le tableau indexé pas associatif.declare -a quotedarray='([0]="1" [1]="2" [2]="3" [3]="4")'
. Ne semble pas aider, pour moi.Êtes-vous sûr de vous? Merci d'essayer de nouveau. Il est impossible d'obtenir votre résultat si vous avez défini le tableau de cette façon
declare -a quotedarray=(1 2 "3 4")
bien que vous soulevez un point intéressant, à mon exemple, semble être mal en quelque sorte.
Si vous obtenez le résultat
declare -a quotedarray='([0]="1" [1]="2" [2]="3" [3]="4")'
, puis le quotedarray doivent être définies afin de(1 2 3 4)
avec les quatre éléments. Veuillez vérifier le tableau, ou videz-le et recommencez.Merci d'avoir signalé le problème, il s'avère que j'ai besoin d'un bash script pour montrer le problème j'ai donc modifié l'exemple.
OriginalL'auteur weynhamz
Lourd méthode (qui ne cite les arguments contenant des espaces):
De sortie:
Par la façon dont, en ce qui concerne
quoting is lost on this pass
, notez que les guillemets sont jamais enregistré." "
est un caractère spécial qui indique l'environnement pour traiter tout ce qui est à l'intérieur comme un simple champ/argument (c'est à dire pas de split). D'autre part, les citations littérales (tapé comme ça\"
) sont préservés.OriginalL'auteur doubleDown
Une autre approche
Utilisation:
$ bash --version
OriginalL'auteur kyb
Je tiens à mettre le code dans une fonction de sorte qu'il est plus facile de réutiliser et de document:
Noter que j'ai ajouté la virgule dans la solution parce que je suis de la génération de code avec un script bash.
[EDIT: correction du problème qui EM0 a souligné qu'il est de retour ['bleu',]]
['blue',]
pour moi.OriginalL'auteur Michael Potter