Existe-t-il un moyen d'get des arguments shell * réels * (non interprétés) dans une fonction ou un script?

J'ai un posix fonction que j'utilise dans le shell Git bash sous Windows pour transformer des paths de style DOS en paths de style Unix normaux. Étant donné que les paths de style DOS utilisent une barre oblique inverse comme séparateur, je dois citer l'argument path pour éviter que les barres obliques inverses utilisées par le shell ne désignent le caractère suivant comme un littéral. Y at-il un moyen d'get l'argument non interprété de l'intérieur de ma fonction, de sorte que je n'ai pas besoin de le citer?

Voici ma fonction, si cela aide:

 function posix() { echo $1 | sed -e 's|\\|/|g' | sed -re 's|^(.)\:|/\L\1|' } 

(En passant, je me réjouis de tous les commentaires avec des conseils pour améliorer la fonction par d'autres moyens sans rapport avec la résolution du problème de citation / shell-interprétation.)

Les arguments shell non interprétés sont $1 , $2 , etc. Vous devez placer leur expansion entre guillemets doubles dans la plupart des contexts, afin d'éviter que la valeur du paramètre ne soit plus étendue. "$@" vous donne la list de tous les parameters.

Par exemple, si vous voulez transmettre un argument du script shell à votre fonction, appelez-le comme ceci:

 first_argument_as_filename_in_unix_syntax=$(posix "$1") 

Les guillemets doubles sont nécessaires. Si vous écrivez posix $1 , alors ce que vous passez n'est pas la valeur du premier paramètre, mais le résultat de l'exécution de la division et de la superposition des mots sur la valeur du premier paramètre. Vous aurez besoin d'utiliser correctement citer lorsque vous appelez le script, aussi. Par exemple, si vous écrivez ceci dans bash:

 myscript c:\path with spaces\somefile 

alors les arguments réels, non interprétés de myscript seront c:path , with et spacessomefile . Alors ne fais pas ça.

Votre fonction posix est incorrecte, encore une fois parce qu'elle manque de guillemets doubles autour $1 . Mettez toujours des guillemets doubles autour des substitutions de variables et de commands: "$foo" , "$(foo)" . Il est plus facile de se callbacker cette règle que les exceptions où vous n'avez pas réellement besoin des citations.

echo fait son propre traitement dans certains cas, et l'appel des process externes est lent (surtout sous Windows). Vous pouvez faire tout le traitement à l'intérieur de bash.

 posix () { path="${1//\\//}" case "$path" in ?:*) drive="${p:0:1}"; drive="${drive,}"; p="/$drive/${p:2}";; esac printf %s "$p" } 

La fonction zsh à laquelle jw013 fait allusion ne fait pas ce que vous semblez penser. Vous pouvez mettre noglob devant une command, et zsh n'effectue pas de globbing (c'est-à-dire la génération de nom de file, c'est-à-dire l'expansion des caractères generics) sur les arguments. Par exemple, dans zsh, si vous écrivez noglob locate *foo*bar* , alors locate est appelé avec l'argument *foo*bar* . Vous cacherez typiquement le builtin noglob derrière un alias. Cette fonctionnalité n'est pas pertinente pour ce que vous essayez de faire.

Alors que d'autres réponses peuvent être correctes en déclarant que vous ne pouvez pas recevoir de données shell "non interprétées" par les moyens qu'elles mentionnent, ils ont tort de nier catégoriquement comme une possibilité. Vous pouvez certainement le recevoir avant que le shell ne l'interprète si vous requestz au shell de ne pas l'interpréter. L'humble POSIX heredoc rend cela tout simplement possible:

 % sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<'_EOF_' > c:\some\stupid\windows\place > _EOF_ /drive/c/some/stupid/windows/place 

EDIT1:

Afin de transmettre une telle string à une fonction shell en tant qu'argument shell, vous allez devoir la stocker dans une variable shell. En général, vous ne pouvez pas simplement var=<<'HEREDOC' malheureusement, mais POSIX spécifie l'argument -r à la read embeddede:

 % man read 

MANUEL DU PROGRAMMATEUR POSIX

Par défaut, sauf si l'option -r est spécifiée, la barre oblique inverse ('\') agira comme un caractère d'échappement, comme décrit dans Escape Character (Backslash). Si l'input standard est un périphérique terminal et que le shell appelant est interactif, read doit requestr une ligne de continuation lorsque:

  • Le shell lit une ligne d'input se terminant par une barre oblique inverse, sauf si l'option -r est spécifiée.

  • Un ici-document n'est pas terminé après qu'une nouvelle ligne est input.

Lorsqu'ils sont combinés, read et l' heredoc font une matière sortingviale et portable, même si cela peut ne pas sembler très intuitif au début:

 % _stupid_mspath_fix() { > sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<_EOF_ >> ${1} >> _EOF_ > } % read -r _stupid_mspath_arg <<'_EOF_' > c:\some\stupid\windows\place > _EOF_ % _stupid_mspath_fix ${_stupid_mspath_arg} /drive/c/some/stupid/windows/place 

EDIT2:

Probablement vous avez remarqué la différence entre les deux heredocs dans le deuxième exemple. Le heredoc _EOF_ au sein de la fonction est non guillemets, tandis que celui alimenté par read est guillemets. De cette manière, le shell est chargé d'effectuer une expansion sur l' heredoc avec un terminateur non heredoc , mais de ne pas le faire lorsque son terminateur est cité. Il ne se casse pas lors de l'expansion de l' heredoc non heredoc dans la fonction car la valeur de la variable qu'elle développe est déjà définie comme une string citée et ne l'parsing pas deux fois.

Probablement ce que vous voulez faire implique de canaliser votre path Windows à partir de la sortie d'une command dans l'input d'un autre dynamicment. La substitution de command au sein d'un heredoc rend cela possible:

 % _stupid_mspath_fix() { > sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<_EOF_ >> ${1} >> _EOF_ > } % read -r _stupid_mspath_arg <<'_EOF_' > c:\some\stupid\windows\place > _EOF_ % _stupid_mspath_fix ${_stupid_mspath_arg} /drive/c/some/stupid/windows/place % read -r _second_stupid_mspath_arg <<_EOF_ > $(printf ${_stupid_mspath_arg}) > _EOF_ % _stupid_mspath_fix ${_second_stupid_mspath_arg} /drive/c/some/stupid/windows/place 

Donc, fondamentalement, si vous pouvez produire de manière fiable les backslashes de certaines applications (j'ai utilisé printf ci-dessus), puis exécuter cette command dans $(...) et en enfermant dans un heredoc non heredoc passé à une autre application qui peut accepter de manière fiable les antislash en input tels que read et sed ci-dessus) contournera l'parsing du shell de vos antislashs complètement. Le fait de savoir si les applications peuvent gérer les barres obliques inversées en tant qu'input / sortie est quelque chose que vous devrez découvrir par vous-même.

Pas ssortingctement pertinent à la question:

Dans la réponse de Gilles, il recommand le formulaire d'extension du paramètre ${var/search/replace} qui, bien que cool, n'est pas POSIX. C'est définitivement un bashisme. Cela n'a pas d'importance pour moi, mais dans ses modifications, il a conservé le nom de la fonction posix () , ce qui peut être trompeur pour certains.

Sur cette note, la fonction posix () l'article initial utilise l'argument regex sed -r très pratique, mais ce n'est pas non plus POSIX. POSIX ne spécifie pas un argument regex étendu pour sed , et son utilisation est donc probablement peu fiable.

Mon count sur stack overflow ne date que de quelques jours, mais j'ai posté quelques réponses traitant spécifiquement de l'extension de parameters POSIX à partir de ma page de profil et dans laquelle j'inclus des guillemets POSIX des lignes direcsortingces et des liens vers celles-ci. Vous en findez également quelques-uns dans lesquels je démontrerai d'autres utilisations de l' heredoc , telles que la lecture d'un script shell entier dans une variable shell, l'parsing et la manipulation par programmation, puis enfin l'exécution de sa nouvelle version. Je dis juste.

Vous ne pouvez pas avoir le process shell "sans interprétation " input. Ce que vous tapez à la command line est juste une string de caractères précisément destinée à être interprétée par le shell. Vous ne pouvez pas faire en sorte que le shell transmette vos caractères littéraux et typés à une fonction ou à une command, car il doit les interpréter pour savoir quelle command / fonction invoquer et avec quels arguments! Lorsque vous tapez quelque chose à l'invite de command, vous devez accepter que vous devez taper selon les règles d'interprétation du shell (car vous utilisez un shell!).

Les règles d'interprétation des coquilles sont très utiles. Plutôt que de vous gêner, ils vous donnent la possibilité d'instruire le shell à faire ce que vous voulez, y compris en spécifiant des arguments arbitraires. Sans interprétation, il est impossible pour le shell d'extraire une action pour s'exécuter précisément à partir de votre input. L'interprétation implique des caractères spéciaux (comme l'espace), et sans s'échapper, il n'y aurait aucun moyen de transmettre ces caractères à une command.

En ce qui concerne l'interprétation elle-même, j'ai toujours trouvé la documentation bash très bonne. En bref, des choses comme l'expansion tilde se produisent très tôt (et l'expansion tilde seulement dans certaines situations). Ensuite, la substitution de variables et la division de mots se produisent, et enfin le regroupement.