J'ai un script wrapper qui fait du travail puis passe les paramètres d'origine sur un autre outil:
#!/bin/bash # ... other_tool -a -b "$@"
Cela fonctionne bien, sauf si le "autre outil" est exécuté en sous-cas:
#!/bin/bash # ... bash -c "other_tool -a -b $@"
Si j'appelle mon script wrapper comme ceci:
wrapper.sh -x "blah blup"
Alors, seul le premier argument original (-x) est remis à "other_tool". En réalité, je ne crée pas un sous-ensemble, mais je passe les arguments originaux à un shell sur un téléphone Android, ce qui ne devrait pas faire de différence:
#!/bin/bash # ... adb sh -c "other_tool -a -b $@"
La commande printf
de Bash comporte une fonctionnalité qui cite / s'échappe, quelle que soit la chaîne, tant que le parent et le subshell sont en fait bash, cela devrait fonctionner:
#!/bin/bash quoted_args="$(printf " %q" "$@")" # Note: this will have a leading space before the first arg # echo "Quoted args:$quoted_args" # Uncomment this to see what it's doing bash -c "other_tool -a -b$quoted_args"
Notez que vous pouvez également le faire en une seule ligne: bash -c "other_tool -a -b$(printf " %q" "$@")"
Changer $@
à $*
. J'ai fait un petit test local et cela fonctionne dans mon cas.
#!/bin/sh bash -c "echo $*" bash -c "echo $@"
Enregistrer comme test.sh
et le rendre exécutable donne
$ ./test.sh foo bar foo bar foo
Il existe une différence subtile entre $*
et $@
, comme vous pouvez le constater. Voir par exemple http://ss64.com/bash/syntax-parameters.html
Pour la question de suivi dans les commentaires: vous devez échapper, par exemple, à l'espace blanc "deux fois" pour passer une chaîne avec un séparateur comme argument combiné, par exemple avec test.sh
modifié à un wrapper wc
:
#!/bin/sh bash -c "wc $*"
Cela marche:
$ touch test\ file $ ./test.sh -l "test\ file" 0 test file
mais:
$ ./test.sh -l "test file" wc: test: No such file or directory wc: file: No such file or directory 0 total
Aucune solution ne fonctionne bien. Il suffit de passer x / \ \ "b \" / aaaaa / \ 'xxx \ aaaa \' / zz \ "offf \" comme paramètre et ils échouent.
Voici une enveloppe simple qui gère chaque cas. Notez comment il échappe à chaque argument deux fois.
#!/usr/bin/env bash declare -a ARGS COUNT=$# for ((INDEX=0; INDEX<COUNT; ++INDEX)) do ARG="$(printf "%q" "$1")" ARGS[INDEX]="$(printf "%q" "$ARG")" shift done ls -l ${ARGS[*]}
Ca manque parce que vous contraignez un tableau (les paramètres de position) dans une chaîne. "$@"
Est magique car il vous donne chaque paramètre séparé comme une chaîne correctement cité. L'ajout de texte supplémentaire casse la magie: "blah $@"
est juste une seule chaîne.
Cela peut vous rapprocher:
cmd="other_tool -a -b" for parm in "$@"; do cmd+=" '$parm'"; done adb sh -c "$cmd"
Bien sûr, tout paramètre contenant une seule citation entraînera des problèmes.
Ok, plus d'explications:
$ cat /tmp/test.sh #! /bin/bash echo '$@='"$@" set -v # "debug" sh -c 'echo $@' "$@" # gremlins steal the first option sh -c 'echo $@' -- "$@" # We defend the option with two knifes $ bash -e /tmp/test.sh first second third $@=first second third sh -c 'echo $@' "$@" # gremlins steal the first option second third sh -c 'echo $@' -- "$@" # We defend the option with two knifes first second third
#! /bin/bash sh -c 'other_tool -a -b "$@"' -- "$@"