Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用wordexp时保留引号_C_Linux - Fatal编程技术网

C 使用wordexp时保留引号

C 使用wordexp时保留引号,c,linux,C,Linux,我正在尝试使用wordexp函数对一些字符串进行类似shell的扩展wordexp删除单引号和双引号,但我想保留它们。我最初的想法是用另一对引号(这次是转义的)包围输入字符串中的所有引号对,而wordexp应该保持不变(或者相反)。不幸的是 对于更复杂的输入,这将失败 例如,对于““TEST”“”,我想以\'\““TEST\'\'\“\'\'结束,我编写了以下代码片段来演示使用我的方法时实际发生的情况: #include <stdio.h> #include <wordexp.

我正在尝试使用
wordexp
函数对一些字符串进行类似shell的扩展
wordexp
删除单引号和双引号,但我想保留它们。我最初的想法是用另一对引号(这次是转义的)包围输入字符串中的所有引号对,而
wordexp
应该保持不变(或者相反)。不幸的是 对于更复杂的输入,这将失败

例如,对于
““TEST”“”
,我想以
\'\““TEST\'\'\“\'\'
结束,我编写了以下代码片段来演示使用我的方法时实际发生的情况:

#include <stdio.h>
#include <wordexp.h>

static void expansion_demo(char const *str)
{
    printf("Before expansion: %s\n", str);

    wordexp_t exp;
    wordexp(str, &exp, 0);
    printf("After expansion: %s\n", exp.we_wordv[0]);
    wordfree(&exp);
}

int main(void)
{
    char const *str1 = "\\''\\\"\"\"\\\"TEST1\\\"\"\"\\\"'\\'";
    expansion_demo(str1);

    char const *str2 = "'\\'\"\\\"\\\"\"TEST2\"\\\"\\\"\"\\''";
    expansion_demo(str2);

    return 0;
}
这会失败,因为双引号嵌套在单引号中 在这种情况下,天真地用转义引号包围每对引号是行不通的(尽管我不知道为什么会发生segfault)

我还考虑过用其他ascii字符临时交换引号,但是没有任何引号不能作为有效shell命令的一部分

有没有办法让它适应我想要的?或者更简单的方法?

分段错误 在代码中,第二个测试字符串:

char const *str2 = "'\\'\"\\\"\\\"\"TEST2\"\\\"\\\"\"\\''";
产生语法错误。在这样的字符串上处理C或shell转义规则有点可怕,但是您可以分析在字符串末尾有一个不匹配的单引号。将C字符串文字转换为字符串将产生:

'\'"\"\""TEST2"\"\""\''
分析时,关键字符由插入符号标记:

'\'"\"\""TEST2"\"\""\''
^^^^^ ^ ^^    ^^ ^ ^^ ^
12345 6 78    91 1 11 1
               0 1 23 4
  • 起始单引号字符串
  • 反斜杠(在单个带引号的字符串中没有特殊含义)
  • 结束单引号字符串
  • 起始双引号字符串
  • 第一个转义双引号(字符串的一部分)
  • 第二个转义双引号(字符串的一部分)
  • 结束双引号字符串
  • 单词
    TEST2
    是引号外的纯文本(字符串的一部分)
  • 起始双引号字符串
  • 第一个转义双引号(字符串的一部分)
  • 第二个转义双引号(字符串的一部分)
  • 结束双引号字符串
  • 转义单引号(字符串的一部分)
  • 单引号字符串的开头
  • 因为最后一个单引号字符串没有结尾,所以出现了语法错误,
    wordexp()
    的返回值是
    WRDE_syntax
    ,这说明了这一点。由于
    exp
    结构在
    exp.we\u wordv
    成员中设置了空指针,因此会出现分段错误

    此更安全的代码版本演示了以下内容:

    /* SO 5246-1162 */
    #include <stdio.h>
    #include <wordexp.h>
    
    static const char *worderror(int errnum)
    {
        switch (errnum)
        {
        case WRDE_BADCHAR:
            return "One of the unquoted characters - <newline>, '|', '&', ';', '<', '>', '(', ')', '{', '}' - appears in an inappropriate context";
        case WRDE_BADVAL:
            return "Reference to undefined shell variable when WRDE_UNDEF was set in flags to wordexp()";
        case WRDE_CMDSUB:
            return "Command substitution requested when WRDE_NOCMD was set in flags to wordexp()";
        case WRDE_NOSPACE:
            return "Attempt to allocate memory in wordexp() failed";
        case WRDE_SYNTAX:
            return "Shell syntax error, such as unbalanced parentheses or unterminated string";
        default:
            return "Unknown error from wordexp() function";
        }
    }
    
    static void expansion_demo(char const *str)
    {
        printf("Before expansion: [%s]\n", str);
        wordexp_t exp;
        int rc;
        if ((rc = wordexp(str, &exp, 0)) == 0)
        {
            for (size_t i = 0; i < exp.we_wordc; i++)
                printf("After expansion %zu: [%s]\n", i, exp.we_wordv[i]);
            wordfree(&exp);
        }
        else
            printf("Expansion failed (%d: %s)\n", rc, worderror(rc));
    }
    
    int main(void)
    {
        char const *str1 = "\\''\\\"\"\"\\\"TEST1\\\"\"\"\\\"'\\'";
        expansion_demo(str1);
    
        char const *str2 = "'\\'\"\\\"\\\"\"TEST2\"\\\"\\\"\"\\''";
        expansion_demo(str2);
    
        return 0;
    }
    
    wordexp()
    做什么 该函数的设计目的是(或多或少)执行与shell相同的扩展,如果将字符串作为命令行的一部分提供给shell。这里有一个简单的程序可以说明这一点。这是对-源文件
    wexp79.c
    的改编

    #include "stderr.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <wordexp.h>
    
    static const char *worderror(int errnum)
    {
        switch (errnum)
        {
        case WRDE_BADCHAR:
            return "One of the unquoted characters - <newline>, '|', '&', ';', '<', '>', '(', ')', '{', '}' - appears in an inappropriate context";
        case WRDE_BADVAL:
            return "Reference to undefined shell variable when WRDE_UNDEF was set in flags to wordexp()";
        case WRDE_CMDSUB:
            return "Command substitution requested when WRDE_NOCMD was set in flags to wordexp()";
        case WRDE_NOSPACE:
            return "Attempt to allocate memory in wordexp() failed";
        case WRDE_SYNTAX:
            return "Shell syntax error, such as unbalanced parentheses or unterminated string";
        default:
            return "Unknown error from wordexp() function";
        }
    }
    
    static void do_wordexp(const char *name)
    {
        wordexp_t wx = { 0 };
        int rc;
        if ((rc = wordexp(name, &wx, WRDE_NOCMD | WRDE_SHOWERR | WRDE_UNDEF)) != 0)
            err_remark("Failed to expand word [%s]\n%d: %s\n", name, rc, worderror(rc));
        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)
        {
            char *buffer = 0;
            size_t buflen = 0;
            int length;
            while ((length = getline(&buffer, &buflen, stdin)) != -1)
            {
                buffer[length-1] = '\0';
                do_wordexp(buffer);
            }
            free(buffer);
        }
        else
        {
            for (int i = 1; i < argc; i++)
                do_wordexp(argv[i]);
        }
        return 0;
    }
    
    它将产生:

    Expansion of [*.c]:
    1: [esc11.c]
    2: [so-5246-1162-a.c]
    3: [so-5246-1162-b.c]
    4: [wexp19.c]
    5: [wexp79.c]
    Expansion of [*[mM]*]:
    1: [README.md]
    2: [esc11.dSYM]
    3: [makefile]
    4: [so-5246-1162-b.dSYM]
    5: [wexp19.dSYM]
    6: [wexp79.dSYM]
    Expansion of [*.[ch] *[mM]* ~/.profile $HOME/.profile]:
    1: [esc11.c]
    2: [so-5246-1162-a.c]
    3: [so-5246-1162-b.c]
    4: [wexp19.c]
    5: [wexp79.c]
    6: [README.md]
    7: [esc11.dSYM]
    8: [makefile]
    9: [so-5246-1162-b.dSYM]
    10: [wexp19.dSYM]
    11: [wexp79.dSYM]
    12: [/Users/jleffler/.profile]
    13: [/Users/jleffler/.profile]
    
    请注意它是如何扩展波浪符号和
    $HOME

    转义字符串 看起来,您所追求的是保留字符串的代码,例如

    '""TEST""'
    
    通过外壳进行扩展,产生如下输出:

    \''""TEST""'\'
    
    我有一系列函数可以生成一个与之等价的字符串(尽管实际输出与我展示的不同;这些函数使用蛮力,上面的示例输出生成一个稍微简单的字符串)。此代码在GitHub上的my(Stack Overflow Questions)存储库中作为子目录中的文件
    escape.c
    escape.h
    提供。下面是一个使用
    escape\u simple()
    的程序,它将转义任何包含可移植文件名字符集以外字符的字符串(
    [-a-Za-z0-9.,/])

    正如我所指出的,转义码使用暴力。它输出一个单引号,然后处理字符串,将遇到的每个单引号替换为
    \''
    。这一顺序:

    • 结束当前单引号字符串
    • 添加转义单引号(
      \'
    • 开始(继续)单个带引号的字符串
    在单引号内,只有单引号需要特殊处理。显然,更复杂的解析器将更巧妙地处理字符串开头或结尾的(重复的)单引号,并将识别重复的单引号并对其进行更简洁的编码

    您可以在命令(与函数相反)中使用转义输出,如下所示:

    $ printf "%s\n" ''\''""TEST""'\''' '\'\'''\''\"""\"TEST1\"""\"'\''\'\''' ''\''\'\''"\"\""TEST2"\"\""\'\'''\'''
    '""TEST""'
    \''\"""\"TEST1\"""\"'\'
    '\'"\"\""TEST2"\"\""\''
    $
    
    没有办法声称任何shell代码都很容易阅读;阅读起来极其困难。但复制粘贴会让生活更轻松。

    在代码中,第二个测试字符串:

    char const *str2 = "'\\'\"\\\"\\\"\"TEST2\"\\\"\\\"\"\\''";
    
    产生语法错误。在这样的字符串上处理C或shell转义规则有点可怕,但是您可以分析在字符串末尾有一个不匹配的单引号。将C字符串文字转换为字符串将产生:

    '\'"\"\""TEST2"\"\""\''
    
    分析时,关键字符由插入符号标记:

    '\'"\"\""TEST2"\"\""\''
    ^^^^^ ^ ^^    ^^ ^ ^^ ^
    12345 6 78    91 1 11 1
                   0 1 23 4
    
  • 起始单引号字符串
  • 反斜杠(在单个带引号的字符串中没有特殊含义)
  • 结束单引号字符串
  • 起始双引号字符串
  • 第一个转义双引号(字符串的一部分)
  • 第二个转义双引号(字符串的一部分)
  • 结束双引号字符串
  • 单词
    TEST2
    是引号外的纯文本(字符串的一部分)
  • 起始双引号字符串
  • 第一个转义双引号(字符串的一部分)
  • 第二个转义双引号(字符串的一部分)
  • 结束双引号字符串
  • 转义单引号(字符串的一部分)
  • 单引号字符串的开头
  • 因为最后一个单引号字符串没有结尾,所以出现了语法错误,
    wordexp()
    的返回值是
    WRDE_syntax
    ,这说明了这一点。由于
    exp
    结构在
    $ printf "%s\n" ''\''""TEST""'\''' '\'\'''\''\"""\"TEST1\"""\"'\''\'\''' ''\''\'\''"\"\""TEST2"\"\""\'\'''\'''
    '""TEST""'
    \''\"""\"TEST1\"""\"'\'
    '\'"\"\""TEST2"\"\""\''
    $