Lancer wc en utilisant execvp () reconnaît /home/usr/foo.txt mais pas ~ / foo.txt

J’ai un programme où je veux exécuter la commande wc utilisant execvp ().

Les bits importants sont ici:

 char *argvNew[5]; argvNew[0] = "wc"; argvNew[1] = "/home/user/foo.txt"; argvNew[2] = NULL; execvp(argvNew[0], arvgNew); 

Cela fonctionne très bien et le terminal affiche la sortie de wc . Cependant, lorsque je change de ligne,

 argvNew[1] = "~/foo.txt" 

Je reçois cette erreur dans le terminal:

 wc: '~/foo.txt': No such file or directory 

Exécuter wc ~/foo.txt directement à partir du terminal se comporte exactement comme si vous wc /home/user/foo.txt . Pourquoi execvp a- execvp -il un problème avec ~/ part?

L’extension Tilde ( ~ ) est faite / comprise uniquement par les shells – elle n’est pas étendue dans les programmes C. Donc execvp tente d’interpréter ~ comme faisant partie du nom de fichier (argument de wc ).

Ce que vous pouvez faire, c’est obtenir la valeur du répertoire HOME aide de getenv et le préfixer avec le nom de fichier (par exemple, à l’aide de snprintf ).

Lorsque vous tapez un nom de fichier tel que ~/foo.txt sur la ligne de commande, le shell le développe pour vous avant d’exécuter la commande. Vous devez donc faire cette extension dans votre code C si vous voulez que cela fonctionne – ou utilisez un shell pour le faire pour vous. Ni la fonction execvp() ni la commande wc n’a de problème avec ~ ; il n’y a tout simplement pas de répertoire appelé ~ dans le répertoire actuel (et par conséquent, il n’y a pas de fichier appelé foo.txt dans le répertoire inexistant).

Ce n’est pas si difficile d’écrire le code pour faire le travail (bien que le faire correctement selon POSIX exige une attention aux détails – voir Développement de tilde ).

Cependant, il existe aussi des fonctions POSIX standard qui peuvent aider et faire ce travail, notamment wordexp() . Bien que la norme ne mentionne pas explicitement le développement de tilde, elle mentionne WRDE_NOCMD pour supprimer la substitution de commande . Elle est donc supposée effectuer un travail approfondi et le développement de tilde doit être inclus dans une implémentation conforme.

Voici un code de test simple permettant d’exercer cette fonction:

 #include "stderr.h" #include  #include  /* int wordexp(const char *ressortingct words, wordexp_t *ressortingct pwordexp, int flags); void wordfree(wordexp_t *pwordexp); */ static void do_wordexp(const char *name) { wordexp_t wx = { 0 }; if (wordexp(name, &wx, WRDE_NOCMD) != 0) err_remark("Failed to expand word [%s]\n", name); else { printf("Expansion of [%s]:\n", name); for (size_t i = 0; i < wx.we_wordc; i++) printf("%zu: [%s]\n", i+1, wx.we_wordv[i]); wordfree(&wx); } } int main(int argc, char **argv) { err_setarg0(argv[0]); if (argc <= 1) do_wordexp("~/.profile"); else { for (int i = 1; i < argc; i++) do_wordexp(argv[i]); } return 0; } 

Et voici quelques exemples d’exécution (programme wexp19 construit à partir de wexp19.c ):

 $ wexp19 Expansion of [~/.profile]: 1: [/Users/jonathanleffler/.profile] $ wexp19 '~informix/bin/oninit' '~/bin/rfmt' '~/bin/al ~/bin/b?' '~/bin/f?' '$IXD/bin/onstat' ' ~/bin/ow ' Expansion of [~informix/bin/oninit]: 1: [/Users/informix/bin/oninit] Expansion of [~/bin/rfmt]: 1: [/Users/jonathanleffler/bin/rfmt] Expansion of [~/bin/al ~/bin/b?]: 1: [/Users/jonathanleffler/bin/al] 2: [/Users/jonathanleffler/bin/bk] Expansion of [~/bin/f?]: 1: [/Users/jonathanleffler/bin/fd] 2: [/Users/jonathanleffler/bin/fl] 3: [/Users/jonathanleffler/bin/fm] Expansion of [$IXD/bin/onstat]: 1: [/opt/informix/12.10.FC6/bin/onstat] Expansion of [ ~/bin/ow ]: 1: [/Users/jonathanleffler/bin/ow] $ 

Notez en particulier le résultat du développement de l'argument de ligne de commande entouré de guillemets '~/bin/al ~/bin/b?' ; il est divisé et les mots sont développés séparément. L'avant-dernier argument développe également la variable d'environnement $IXD partir de mon environnement et le dernier exemple montre que les blancs sont supprimés. Les guillemets simples sur la ligne de commande sont nécessaires pour empêcher le shell de faire ce que je veux démontrer avec wordexp() .

Les tests sont exécutés sur un Mac exécutant macOS 10.13.6 High Sierra et utilisant GCC 8.2.0. YMMV!