Когда вы вводите имя файла, например ~/foo.txt
, в командной строке, оболочка раскрывает его для вас перед выполнением команды. Поэтому вы должны выполнить это расширение в своем коде C, если хотите, чтобы оно работало, или использовать оболочку, чтобы выполнить расширение для вас. Ни у функции execvp()
, ни у команды wc
нет проблем с ~
; в текущем каталоге просто нет каталога с именем ~
(и, следовательно, в несуществующем каталоге нет файла с именем foo.txt
).
Не так уж сложно написать код для выполнения работы (хотя для правильного выполнения в соответствии с POSIX требуется внимание к деталям - см. Расширение Tilde ).
Однако существуют также стандартные функции POSIX, которые могут помочь и выполнить эту работу, в частности wordexp()
. Хотя в стандарте явно не упоминается расширение тильды, в нем упоминается WRDE_NOCMD
для подавления подстановки команд , поэтому предполагается, что он должен выполнить тщательную работу, а расширение тильды должно быть включено в соответствующую реализацию.
Вот простой тестовый код, выполняющий эту функцию:
#include "stderr.h"
#include <stdio.h>
#include <wordexp.h>
/*
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;
}
А вот несколько примеров прогонов (программа wexp19
построена из 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]
$
Обратите особое внимание на результат расширения аргумента командной строки, заключенного в кавычки '~/bin/al ~/bin/b?'
; это разделено, и слова отдельно расширены. Следующий за последним аргументом также расширяет переменную окружения $IXD
из моей среды, и в последнем примере показано, что пробелы удалены. Одиночные кавычки в командной строке необходимы, чтобы не дать оболочке делать то, что я хочу продемонстрировать wordexp()
.
Тесты выполняются на Mac с MacOS 10.13.6 High Sierra и с использованием GCC 8.2.0. YMMV!