用于转义 shell 命令参数的 C 函数?

11

在C语言中,我应该使用哪个函数来转义shell命令参数的字符串?

  1. 我有一个字符串:

    This is a string with () characters

  2. 这会导致错误:

    echo This is a string with () characters

  3. 这些是正确的:

    echo "This is a string with () characters"

    echo This is a string with \(\) characters

在C语言中是否有预定义的函数可将#2转换为#3?

5个回答

10

将所有的'替换为'\'',然后将整个字符串用单引号(')括起来是一种安全的方法。即使有嵌入式换行符也适用。另一种方法是在每个字符前插入\,但需要特殊处理换行符,因为Shell会忽略跟在\后面的换行符,而不是当作一个换行符的实例。你必须使用单引号(')将换行符括起来。


1
尝试使用字符串:a'b。对我来说,在bash中echo 'a'b'....不起作用,但是echo 'a'"'"'b'可以... - Erik Aronesty
1
@ErikAronestyпјҡжҲ‘иҜҙиҰҒз”Ё'\''жӣҝжҚў'пјҢиҖҢдёҚжҳҜ\'гҖӮ - R.. GitHub STOP HELPING ICE
请注意,引用 ' 会导致 ''\''',实际上是三个字符串序列,在评估时会被附加。因此这不是真正的引用。 - ManuelSchneid3r
@ManuelSchneid3r:需要引用。您的评论甚至在概念上都不符合shell字段拆分和引号删除的工作方式。请参见http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html。 - R.. GitHub STOP HELPING ICE

3

没有预定义的函数。

然而,我认为只需用单引号括起任何shell参数,并确保单引号被转义即可。

这是PHP中escapeshellarg函数的逻辑,我相信它能够很好地工作。


在Shell的上下文中,请注意使用单引号或双引号进行引用的区别。在双引号中,您还需要转义$和`字符。详见:https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html#Double-Quotes - ManuelSchneid3r
请注意,Shell 不允许在单引号字符串中使用单引号。 - ManuelSchneid3r

2

虽然C语言不是我首选的编程语言,但是在回答相同问题之后,这是我得出的结果。

#include <stdio.h>     // sprintf
#include <stdlib.h>    // malloc
#include <string.h>    // strlen

char* escapeshellarg(char* str) {
    char *escStr;
    int i,
        count = strlen(str),
            ptr_size = count+3;

    escStr = (char *) calloc(ptr_size, sizeof(char));
    if (escStr == NULL) {
        return NULL;
    }
    sprintf(escStr, "'");

    for(i=0; i<count; i++) {
        if (str[i] == '\'') {
                    ptr_size += 3;
            escStr = (char *) realloc(escStr,ptr_size * sizeof(char));
            if (escStr == NULL) {
                return NULL;
            }
            sprintf(escStr, "%s'\\''", escStr);
        } else {
            sprintf(escStr, "%s%c", escStr, str[i]);
        }
    }

    sprintf(escStr, "%s%c", escStr, '\'');
    return escStr;
}

给定 escape'this',它将输出 'escape'\''this'\''',然后可以传递给echo
$ echo 'escape'\''this'\'''
escape'this'

realloc不是非常昂贵的操作吗?我记得可能整个字符串都会被复制到一个新位置。最好在开始时分配2*str_size。虽然你不经常使用带有很多'的参数,但仍然...... - NickSoft

1

没有预定义的内容,需要转义的字符取决于您的 shell。查看您的 shell 文档,并将每个 X 替换为 \X。如果您用双引号 " 括起来的字符串包含一个 ",则需要进行相同的处理。

还要注意,如果您打算封装更复杂的表达式(例如与 ';' 相结合的任何内容),这将变得更加复杂。


1

将每个单引号 ' 替换为 '\'',然后用单引号 ' 将结果字符串括起来:

char *escapeShellArg( char *arg )
{
    char        *esc;
    uint16_t    i,
                j,
                n;

    n = strlen( arg );

    esc = calloc( 1, n * 4 + 3 );

    esc[0] = '\'';
    j = 1;

    for( i = 0; i < n; i++ )
    {
        if( arg[ i ] == '\'' )
        {
            esc[ j   ] = '\'';
            esc[ j+1 ] = '\\';
            esc[ j+2 ] = '\'';
            esc[ j+3 ] = '\'';
            j += 4;
        }
        else
        {
            esc[ j++ ] = arg[ i ];
        }
    }

    esc[ j ] = '\'';

    return esc;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接