我试图做某事,但我可以。我有一个C程序,我想解析所有的参数。让我们更具体一点
编辑:我在缓冲区中读取命令,而不是在程序以argv等开头时。 我使用STDIN的fgets
读取命令让我们说我读了这样的命令行:
ls -la
我想以这种格式保存n
数组中的命令和参数列表:
char ***command; // A list of lists of strings.
command[0][0] = "ls";
command[0][1] = "-l";
command[0][2] = "a";
command[0][3] = NULL;
我想使用execvp执行上述命令,这就是我想要这种格式的原因。另请参阅以下示例
ls -la | grep 1
数组必须如下:
command[0][0] = "ls";
command[0][1] = "-l";
command[0][2] = "a";
command[0][3] = NULL;
command[1][0] = "grep";
command[1][1] = 1;
command[1][2] = NULL;
所以简单地说,我想分割命令并将它们放在2D数组中,基于字符|但也要保持命令参数。
我尝试使用strtok(space char delimeter)执行此操作,然后将它们存储在数组中但我失败了。
你能帮我吗?
谢谢
答案 0 :(得分:1)
以下答案显示了如何将shell分割为C字符串,就像shell在将main
函数作为argc
和argv
传递给ls -la
之前一样。那是argv[0] == "ls"
argv[1] == "-la"
将被分成:
|
但是,由于您希望包含多个与管道字符粘合在一起的命令行,因此首先必须在每个str = "ls -la|grep hello";
...
// Do split on |
...
strs[0] == "ls -la";
strs[1] == "grep hello";
字符处拆分字符串。如您所述,可以使用strtok
完成此操作。
argv
然后将这些命令行进一步拆分为自己的NULL
数组。然后最后将这些组合成一个带有|
分隔符的数组,如你所描述的那样。
因为您在开始时并不知道最终数组的大小。或者就此而言,有多少argv
个符号,你可以首先计算这些符号并分配一个包含所有char **strs = NULL;
char **argvs = NULL;
size_t count = 0;
size_t i = 0;
while (*str) if (*str++ == '|') ++count;
strs = calloc(count, sizeof(char *));
...
// strtok on | and save tokens into strs[i]
...
s的数组:
NULL
现在拆分命令行并在末尾添加// Code for split_commandline below.
for (i = 0; i < count; i++)
{
argvs[i] = split_commandline(strs[i], &argc);
// Make room for NULL at the end of the argv array.
argvs[i] = realloc(argvs[i], (argc + 1) * sizeof(char *));
argvs[i][argc] = NULL;
}
:
"ls -la"
所有人都有点做作,当然可以使用存储,但这样做的步骤很明确。
注意:这不会像原始问题那样将"ls", "-l", "a"
拆分为"ls", "-la"
,而是"-la"
。我不确定为什么会这样,但是由于ls
的含义特定于sh
程序,因此需要针对单个命令进行黑客攻击。
<强>在Unix / Linux 强>
你可以使用wordexp
来做这件事。但是,并不是说这有一些安全隐患你应该知道。即它将扩展shell变量,如果不是所有的实现都会导致调用wordexp
。
注意:即使在调用wordfree
之后,似乎OSX 10.9.5也会在wchar_t *
中泄漏内存。有关详细信息,请参阅Is wordexp in libc on OSX 10.9.5 known to leak?。
<强>窗强> 我知道这个问题只是针对Linux标记的。但其他人可能对多平台解决方案感兴趣。
您可以在这里使用CommandLineToArgvW
。请注意,这是针对char *
的,因此下面的示例代码首先从wchar_t *
转换为char *
,执行拆分,然后转换回char *
以获取一致的API两个平台。
在编写此实现后,我还发现__getmainargs
支持char **split_commandline(const char *cmdline, int *argc)
{
size_t i;
char **argv = NULL;
assert(argc);
if (!cmdline)
{
return NULL;
}
// Posix.
#ifndef _WIN32
{
int ret;
wordexp_t p;
memset(&p, 0, sizeof(p));
// Note! This expands shell variables (might be a security issue).
if ((ret = wordexp(cmdline, &p, 0)))
{
return NULL;
}
*argc = p.we_wordc;
if (!(argv = calloc(*argc, sizeof(char *))))
{
goto fail;
}
for (i = 0; i < p.we_wordc; i++)
{
if (!(argv[i] = strdup(p.we_wordv[i])))
{
goto fail;
}
}
// Note that on some OSX versions this does not free all memory (10.9.5)
wordfree(&p);
return argv;
fail:
p.we_offs = 0;
wordfree(&p);
}
#else // WIN32
{
// TODO: __getmainargs is an alternative... https://msdn.microsoft.com/en-us/library/ff770599.aspx
wchar_t **wargs = NULL;
size_t needed = 0;
wchar_t *cmdlinew = NULL;
size_t len = strlen(cmdline) + 1;
if (!(cmdlinew = calloc(len, sizeof(wchar_t))))
{
goto fail;
}
if (!MultiByteToWideChar(CP_ACP, 0, cmdline, -1, cmdlinew, len))
{
goto fail;
}
if (!(wargs = CommandLineToArgvW(cmdlinew, argc)))
{
goto fail;
}
if (!(argv = calloc(*argc, sizeof(char *))))
{
goto fail;
}
// Convert from wchar_t * to ANSI char *
for (i = 0; i < *argc; i++)
{
// Get the size needed for the target buffer.
// CP_ACP = Ansi Codepage.
needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1,
NULL, 0, NULL, NULL);
if (!(argv[i] = malloc(needed)))
{
goto fail;
}
// Do the conversion.
needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1,
argv[i], needed, NULL, NULL);
}
if (wargs) LocalFree(wargs);
free(&cmdlinew);
return argv;
fail:
if (wargs) LocalFree(wargs);
free(&cmdlinew);
}
#endif // WIN32
if (argv)
{
for (i = 0; i < *argc; i++)
{
if(argv[i]) free(argv[i]);
argv[i] = NULL;
}
free(argv);
}
return NULL;
}
,但我还没有尝试使用它。
代码示例:
<Grid x:Name="LayoutRoot" Background="Black">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1" x:Name="ContentRoot" RenderTransformOrigin="0.5,0.5" Opacity="0.5" >
<Image x:Name="Image" Source="ms-appx:///Assets/AccountManagement/avatar.png" VerticalAlignment="Center" Stretch="UniformToFill" ScrollViewer.HorizontalScrollBarVisibility="Visible" HorizontalAlignment="Center" Height="300" RenderTransformOrigin="0.5,0.5" >
<Image.RenderTransform>
<CompositeTransform x:Name="ImageCompositeTransform" Rotation="0" TranslateX="0" TranslateY="0" ScaleX="1" ScaleY="1" />
</Image.RenderTransform>
</Image>
</Grid>
<Ellipse ManipulationDelta="Ellipse_ManipulationDelta" x:Name="Ellipse" Stroke="White" StrokeThickness="1" StrokeDashArray="3,3" Height="300" Width="300" Canvas.ZIndex="1" Margin="0" Grid.Row="1" VerticalAlignment="Center" d:LayoutOverrides="Height" HorizontalAlignment="Center" ManipulationMode="All" RenderTransformOrigin="0.5,0.5" >
<Ellipse.Fill>
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding Source, ElementName=Image}">
<ImageBrush.Transform>
<CompositeTransform CenterX="150" CenterY="150" ScaleX="{Binding ScaleX, ElementName=ImageCompositeTransform}" ScaleY="{Binding ScaleY, ElementName=ImageCompositeTransform}" TranslateX="{Binding TranslateX, ElementName=ImageCompositeTransform}" TranslateY="{Binding TranslateY, ElementName=ImageCompositeTransform}" Rotation="{Binding Rotation, ElementName=ImageCompositeTransform}" />
</ImageBrush.Transform>
</ImageBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
答案 1 :(得分:0)
*使用 getopt ... 有关getopt的更多信息,请参阅 &#34; man 3 getopt&#34; *
int main (int argc, char **argv)
{
int opt, flgl = 0, flga = 0;
int indx;
while ((opt = getopt (argc, argv, "la")) != ERROR) {
switch (opt) {
case 'l':
flgl = 1; //printf ("%c", opt);
break;
case 'a':
flga = 1; //printf ("%c", opt);
break;
default:
fprintf (stderr, "missing file operand\n");
break;
}
}
if (optind >= argc) {
fprintf (stderr, "missing file operand\n");
return FAILURE;
}
for (indx = optind ; indx < argc ; indx++)
call_rm (argv[indx], flgd, flgr);
return SUCCESS;
}