使用execvp()运行’wc’识别/home/usr/foo.txt但不识别〜/ foo.txt

我有一个程序,我想使用execvp()运行命令wc

重要的部分在这里:

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

这很好用,终端显示wc的输出。 但是,当我将行更改为:

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

我在终端中收到此错误:

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

直接从终端运行wc ~/foo.txt的行为与运行wc /home/user/foo.txt完全相同。 为什么execvp~/ part存在问题?

Tilde( ~ )扩展仅由shell完成/理解 – 它没有在C程序中扩展。 所以execvp试图解释~作为文件名的一部分( wc参数)。

您可以做的是使用getenv获取HOME目录值,并使用文件名作为前缀(例如,使用snprintf )。

在命令行中键入文件名(如~/foo.txt时,shell会在运行命令之前为您展开它。 因此,如果您希望它能够工作,您必须在C代码中进行扩展 – 或者使用shell为您进行扩展。 execvp()函数和wc命令都没有~任何问题; 在当前目录中根本没有名为~的目录(因此在不存在的目录中没有名为foo.txt的文件)。

编写代码来完成这项工作并不是那么难(尽管按POSIX正确地执行此操作需要注意细节 – 请参阅Tilde扩展 )。

但是,还有标准的POSIX函数可以帮助并完成这项工作,特别是wordexp() 。 尽管该标准没有明确提及波浪扩展,但它确实提到了WRDE_NOCMD以抑制命令替换 ,因此它应该做一个彻底的工作,波形扩展应该包含在一致的实现中。

以下是一些执行该function的简单测试代码:

 #include "stderr.h" #include  #include  /* int wordexp(const char *restrict words, wordexp_t *restrict 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; } 

这里有几个示例运行(程序wexp19wexp19.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] $ 

特别注意扩展引用括起来的命令行参数'~/bin/al ~/bin/b?' ; 它是分开的,单词是分开扩展的。 倒数第二个参数$IXD从我的环境中扩展环境变量$IXD ,最后一个示例显示空白被删除。 命令行上的单引号是必要的,以阻止shell执行我想要演示wordexp()

测试在运行macOS 10.13.6 High Sierra的Mac上运行,并使用GCC 8.2.0。 因人而异!