Comment garder les guillemets dans Bash arguments?
J'ai un script Bash où je veux garder les guillemets dans les arguments passés.
Exemple:
./test.sh this is "some test"
alors je veux utiliser ces arguments, et de ré-utiliser, y compris les citations et des citations autour de l'ensemble de la liste d'arguments.
J'ai essayé d'utiliser \"$@\"
, mais qui supprime les guillemets à l'intérieur de la liste.
Comment puis-je y arriver?
\"$@\"
est faux -- il ajoute littérale les guillemets pour la première et la dernière arguments."$@"
, sans les barres obliques inverses, est correcte: en elle, les guillemets sont purement syntaxiques. Voir BashFAQ #50 pour une explication de pourquoi passer des listes d'arguments autour des chaînes de caractères est foncièrement erronée dans le shell.- Charles est à droite. Lorsque vous souhaitez passer tous les arguments d'un autre script ou d'une fonction, utiliser "$@" (sans échapper à vos citations).
- Voir cette réponse: la Différence entre les guillemets simples et doubles dans Bash.
- Connexes: Comment puis-je utiliser une variable Bash (string) contenant des citations dans une commande?
Vous devez vous connecter pour publier un commentaire.
Suffit d'utiliser les guillemets simples autour de la chaîne avec les guillemets:
Donc les guillemets à l'intérieur des guillemets simples ont également été interprété comme une chaîne de caractères.
Mais je vous recommande de mettre l'ensemble de la chaîne de caractères entre guillemets simples:
Afin de comprendre ce que le shell est en train de faire ou plutôt de l'interprétation des arguments dans les scripts, vous pouvez écrire un petit script comme ceci:
Ensuite vous pourrez voir et tester ce qu'il se passe lors de l'appel d'un script avec différentes chaînes
./test.sh
alors c'est la bonne réponse, mais si vous êtes à la création de./test.sh
, puis la réponse de Chris Dodd c'est la meilleure solution.test.sh
, mais seulement dans le cas oùtest.sh
est écrit pour utilisereval
mal est approprié. Et franchement, si quelque chose est à l'aide deeval
mal, c'est probablement une assez bonne raison pour arrêter d'utiliser cette chose.à l'aide de
"$@"
va remplacer les arguments sous forme d'une liste, sans avoir à re-découper sur les espaces (ils ont été divisés qu'une fois lorsque le shell script a été appelé), qui est généralement exactement ce que vous voulez si vous voulez juste pour re-passer des arguments à un autre programme.Ce que vous essayez de faire et de quelle manière est-il pas de travail?
xargs
? serait-il travailler sans la re-citant truc? je ne le crois pasxargs sh
...)echo "$@" | xargs -t defaults write "${BUNDLEID}" "${KEY}" -dict
dans ce cas, si l'un des paramètres d'entrée, c'est comme "pararm avec des espaces" que cela ne fonctionnerait pas sans les citer trucfind <some find args> | xargs program "$@"
et il va passer les arguments du script d'origine ou de la fonction àprogram
avec pas de réinterprétation. Si vous voulez xargs pour ne pas diviser son ENTRÉE sur des espaces, vous besoin de quelque chose comme{ for a in "$@"; do echo -en "$a\\x0"; done; } | xargs -0 program
echo "nospace" "yes space" | xargs ls "$@"
echo "nospace" "yes space" | xargs -0 ls
echo '"nospace"' '"yes space"' | xargs ls
Dans le premier cas, 3 salles de nom transmis àls
parxargs
et dans le 2e cas, un seul (comme prévu) que le 3e cas fonctionne correctement (pas de surprise)echo
--xargs
et"$@"
ne sont pas pertinents. Essayezecho -ne "nospace\x0yes space\x0"
comme je l'ai suggéré../yourscript this is "some test"
, puis en exécutant./anotherscript "$@"
va passerthis
,is
, etsome test
que trois arguments distincts grâce àanotherscript
, comme si l'utilisateur avait couru./anotherscript this is "some test"
.-0
extension.". Cela dit, xargs seulement dequotes son stdin, pas son vecteur argument.xargs something "$@"
-- c'est lorsque vous donnez le biberon à un contenu de stdin dexargs
que des précautions telles queprintf '%s\0' "$@" | xargs -0 something
sont nécessaires.Yuku réponse ne fonctionne que si vous êtes le seul utilisateur de votre script, tandis que Dennis Williamson est génial si vous êtes surtout intéressé par l'impression que les cordes, et espérer qu'ils ont pas de citations dans les citations.
Voici une version qui peut être utilisé si vous souhaitez passer tous les arguments comme une grande chaîne entre guillemets argument de la
-c
paramètre debash
ousu
:Donc, tous les arguments obtenir un devis autour d'eux (sans danger si elle n'était pas là avant, pour cette raison), mais également de nous échapper à tout échappe et puis échapper à toutes les citations qui étaient déjà à un argument (la syntaxe
${var//from/to}
global sous-chaîne de substitution).Vous pouvez bien entendu vous cite des trucs qui avaient déjà des espaces dans des, mais il ne sera pas question ici. Un utilitaire de script comme il est d'être en mesure d'avoir un certain ensemble prédéfini de variables d'environnement (ou, avec su, à exécuter des choses comme un certain utilisateur, sans que le désordre de double-échappement tout).
Mise à jour: j'ai récemment eu raison de le faire dans une POSIX façon avec un minimum de bifurcation, qui conduisent à ce script (le dernier printf il y a des sorties de la ligne de commande utilisée pour appeler le script, vous devriez être en mesure de copier-coller afin de l'invoquer avec les mêmes arguments):
Je suis passé à
''
depuis coquilles aussi d'interpréter les choses comme$
et!!
dans""
-citations.` before appending to
$C` - à-d. l'ajout dei="${i//\\/\\\\}"
sinon arguments comme"\\\"asdf"
échouera.$ ./escape-args-to-bash echo "\\\"asdf"
pour obtenir\"asdf
comme$ echo "\\\"asdf"
donne\"asdf
. (Dans le cas où le commentaire ci-dessus n'est pas modifiable, le single " était probablement destiné à être une barre oblique inverse dans backticks qui a fini par s'échapper de la backtick au lieu – est-il un corollaire de Muphry la Loi ici? :))Si on peut faire l'hypothèse qu'un argument qui contient l'espace blanc doit avoir été (et devraient) être cité, alors vous pouvez les ajouter comme ceci:
Voici un exemple d'exécution:
Vous pouvez également insérer littérale tabulations et retours à la ligne à l'aide de Ctrl-V Tab et Ctrl-V Ctrl-J à l'intérieur de simple ou double quotes au lieu d'utiliser échappe dans
$'...'
.Une note sur insertion caractères dans Bash: Si vous utilisez le Vi raccourcis clavier (
set -o vi
) en Bash (Emacs est la valeur par défaut -set -o emacs
), vous devez être en insérer mode pour insérer des caractères. En mode Emacs, vous êtes toujours en mode insertion.Il y a deux moyens sûrs pour ce faire:
1. Shell paramètre d'extension:
${variable@Q}:
Lors de l'expansion d'une variable via
${variable@Q}
:Exemple:
2.
printf %q "$quote-me"
printf
prend en charge citant en interne. Le manuel de l'entrée deprintf
dit:Exemple:
Note le 2ème est un peu plus propre si affichant le texte cité à un humain.
Liées: Pour bash, POSIX sh et zsh: Citation de chaîne avec des guillemets simples plutôt que des barres obliques inverses
!
doit être citée: non cotées:$ echo !foo
-bash: !foo: event not found
Cité:$ echo \!foo
!foo
expand-q
a une erreur:${i@Q}
devrait être${i:Q}
sinon elle échoue avecbash: ${i@Q}: bad substitution
bash
? Il fonctionne comme indiqué sur$BASH_VERSION 4.4.19(1)-release
. Ce que vous faites est probablement un des effets secondaires de${parameter:offset}
oùoffset
est0
, (peut-être parce queatoi()
deQ
donne0
).4.3.48(1)-release
Comme Tom Hale dit, une façon de le faire est avec
printf
à l'aide de%q
de devis échapper.Par exemple:
send_all_args.sh
send_fewer_args.sh
receiver.sh
Exemple d'utilisation:
J'avais besoin de cela pour l'acheminement de tous les arguments d'un autre interprète.
Ce fini pour moi est:
Exemple (si elle est nommée en tant que forward.sh):
(Bien sûr, le script que j'utilise est plus complexe, impliquant dans mon cas nohup et les redirections, etc., mais c'est la partie de la clé.)
Mon problème était similaire et j'ai utilisé mélangé les idées affichées ici.
Nous avons un serveur avec un script PHP qui envoie des e-mails. Et puis nous avons un deuxième serveur qui se connecte à la 1ère serveur via SSH et l'exécute.
Le nom du script est le même sur les deux serveurs et les deux sont en fait exécutées via un script bash.
Sur le serveur 1 (local) script bash que nous venons d':
Cette réside sur
/usr/local/bin/myscript
et est appelé par le serveur distant. Il fonctionne très bien, même pour les arguments contenant des espaces.Mais ensuite, sur le serveur distant, nous ne pouvons pas utiliser la même logique, car le 1er serveur ne recevra pas les citations de
"$@"
. J'ai utilisé les idées de la JohnMudd et Dennis Williamson pour recréer les options et les paramètres de tableau avec des citations. J'aime l'idée d'ajouter échappé devis uniquement lorsque l'élément a des espaces.De sorte que la distance script s'exécute avec:
Noter que j'utilise
"${CSMOPTS[@]}"
pour passer le tableau d'options pour le serveur distant.Merci pour eveyone qui a posté ici! Il m'a vraiment aidé! 🙂
=
dans mes scripts, mais depuis le\"
ne sont ajoutés lorsque les espaces sont détectés,-opt="value"
va réellement devenir-opt=value
. quelque chose comme-opt="another value"
serait envoyé comme"-opt=another value"
mais depuis mon installation l'envoie à un autre script sur une autre machine, il est toujours interprété comme un seul jeton comme prévu. Le script distant reçoit-opt=another value
comme un seul jeton sans citations. Les choses sont très différentes si l'exécution en local si. Vous n'auriez même pas besoin d'échapper à la\"
par exemple.Changé unhammerà l'exemple de l'utilisation de tableau.
"${C[@]}"
comme un argument debash -c
là? E. g. si votre script est appelé avec les argumentsecho foo\"bar"'"fie
foo=( echo bar\"fie"'"fum ); C='';for i in "${foo[@]}"; do C="$C \"${i//\"/\\\"}\""; done; bash -c "$C"
donnebar"fie'fum
Citations sont interprétés par bash et ne sont pas stockés dans les arguments de ligne de commande ou les valeurs d'une variable.
Si vous souhaitez utiliser cité des arguments, vous avez à les citer à chaque fois que vous les utilisez:
Suffit d'utiliser:
Par exemple:
Oui, paraît que c'est pas toujours possible de conserver les guillemets, mais pour la question que j'avais il n'était pas nécessaire.
J'ai un bash fonction de recherche en bas de dossiers de manière récursive et grep pour une chaîne, le problème est le passage d'une chaîne qui a des espaces, tels que "trouver cette chaîne". En la passant à la bash script va ensuite prendre la base de l'argument $n et de le passer à grep, ce qui a grep croire ces différents arguments. La façon dont j'ai résolu ce problème en utilisant le fait que lorsque l'on cite bash pour appeler la fonction, il regroupe les articles dans le devis en un seul argument. J'ai juste besoin de décorer cet argument avec des citations et passer à la commande grep.
Si vous savez quel argument vous recevez en bash qui a besoin de guillemets pour sa prochaine étape, vous pouvez simplement décorer avec des avec des guillemets.
Comme Gary S. Weaver montré dans son code source, les conseils, l'astuce est d'appeler bash avec le paramètre "- c " et de citer le suivant.
par exemple
ou