Comportement étrange de argv lors du passage d'une chaîne contenant"!!!!"

J'ai écrit un petit programme qui prend certains paramètres d'entrée de *argv[] et les imprime. Dans presque tous les cas d'utilisation, mon code fonctionne parfaitement. Un problème se pose uniquement quand j'utilise plus d'un point d'exclamation à la fin de la chaîne que je veux passer en argument ...

Cela fonctionne:

./program -m "Hello, world!"

Cela ne fonctionne pas:

./program -m "Hello, world!!!!"

^^ Si je fais cela, la sortie du programme est soit le double de cette chaîne, soit la commande à laquelle j'ai entré précédemment ./programme.

Cependant, ce que je ne comprends absolument pas: ce qui suit, curieusement, fonctionne:

./program -m 'Hello, world!!!!'

^^ La sortie est exactement ...

Hello, world!!!!

... tout comme souhaité.

Donc, mes questions sont:

  • pourquoi ce comportement étrange se produit-il lorsque vous utilisez plusieurs points d'exclamation dans une chaîne?
  • pour autant que je sache, en C vous utilisez "" pour les chaînes et '' pour les caractères simples. Alors, pourquoi dois-je obtenir le résultat souhaité lors de l'utilisation de '', mais pas lors de l'utilisation de "" comme je le devrais (dans mon la compréhension)?
  • y a-t-il une erreur dans mon code ou que dois-je changer pour pouvoir entrer une chaîne (peu importe si, quoi et combien de signes de ponctuation sont utilisés) et obtenir exactement cette chaîne imprimée?

Les parties pertinentes de mon code:

// this is a simplified example that, in essence, does the same 
// as my (significantly longer) code
int main(int argc, char* argv[]) {
    char *msg = (char *)calloc(1024, sizeof(char));

    printf("%s", strcat(msg, argv[2])); // argv[1] is "-m"

    free(msg);
}

J'ai déjà essayé de copier le contenu de argv[2] dans un tampon char* et d'y ajouter un '', ce qui n'a rien changé.

31
demandé sur dbush 2018-02-08 16:46:52

3 réponses

Ce n'est pas lié à votre code mais au shell qui le démarre.

Dans la plupart des shells, !! est un raccourci pour la dernière commande exécutée. Lorsque vous utilisez des guillemets doubles, le shell permet l'expansion de l'historique (ainsi que la substitution de variables,etc.) dans la chaîne, donc lorsque vous mettez !! à l'intérieur d'une chaîne entre guillemets doubles, il remplace la dernière commande exécutée.

Ce que cela signifie pour votre programme est que tout cela se passe avant votre programme est exécuté, donc, il n'y a pas grand-chose que le programme peut faire, sauf vérifier si la chaîne transmise est valide.

En revanche, lorsque vous utilisez des guillemets simples, le shell ne pas avez aucune substitution et la chaîne est passée au programme non modifiée.

Vous devez donc utiliser des guillemets simples pour passer cette chaîne. Vos utilisateurs auraient besoin de le savoir s'ils ne veulent pas de substitution. L'alternative consiste à créer un script shell wrapper qui invite l'utilisateur à transmettre la chaîne, ensuite, le script appellerait par la suite Votre programme avec les arguments appropriés.

68
répondu dbush 2018-02-08 16:57:17

Le shell fait l'expansion dans les chaînes entre guillemets doubles. Et si vous lisez la page de manuel Bash (en supposant que vous utilisez Bash, qui est la valeur par défaut sur la plupart des distributions Linux), alors si vous regardez la section D'Expansion de L'historique , vous verrez que !! signifie

Reportez-vous à la commande précédente.

Donc !!!! dans votre chaîne entre guillemets doubles s'étendra à la commande précédente, deux fois.

Une telle expansion n'est pas faite pour les chaînes entre guillemets simples.

Donc le problème n'est pas dans votre programme, c'est dû à l'environnement (le shell) appelant votre programme.

9
répondu Some programmer dude 2018-02-08 13:51:24

En plus des réponses fournies, vous devez vous rappeler que echo est votre ami shell. Si vous préfixez votre commande avec "echo", vous verrez quel shell envoie réellement à votre script.

echo ./program -m "Hello, world!!!!"

Cela vous aurait montré une certaine étrangeté et aurait pu vous aider à vous orienter dans la bonne direction.

8
répondu UncleCarl 2018-02-08 18:32:01