Bash 在macOS中创建外壳转义POSIX路径

Bash 在macOS中创建外壳转义POSIX路径,bash,macos,cocoa,posix,core-foundation,Bash,Macos,Cocoa,Posix,Core Foundation,我需要从完整的POSIX路径(从根路径开始)创建一个字符串,这样它就可以直接粘贴到Unix shell中,如bash,例如在Terminal.app中,而不需要在路径周围加引号 (我实际上并没有将字符串传递给shell,而是需要它来传递给另一个程序。该程序需要的路径与您将文件拖动到Terminal.app中时得到的路径相同) 为此,我需要通过在字符串前面加反斜杠来转义字符串中的至少任何空格。还有更多的角色 例如,此路径: /directory/-as“*+ 将按如下方式进行转义: def quo

我需要从完整的POSIX路径(从根路径开始)创建一个字符串,这样它就可以直接粘贴到Unix shell中,如
bash
,例如在
Terminal.app
中,而不需要在路径周围加引号

(我实际上并没有将字符串传递给shell,而是需要它来传递给另一个程序。该程序需要的路径与您将文件拖动到
Terminal.app
中时得到的路径相同)

为此,我需要通过在字符串前面加反斜杠来转义字符串中的至少任何空格。还有更多的角色

例如,此路径:

/directory/-as“*+

将按如下方式进行转义:

def quote(s):
    """Return a shell-escaped version of the string *s*."""
    if not s:
        return "''"
    if _find_unsafe(s) is None:
        return s

    # use single quotes, and put single quotes into double quotes
    # the string $'b is then quoted as '$'"'"'b'
    return "'" + s.replace("'", "'\"'\"'") + "'"
/directory/-as\“\\\\*+

执行转换的安全算法是什么?我可以逃避每一个角色,但那太过分了

似乎没有框架函数可以执行此操作,因此我需要使用字符串操作进行替换


为了保守(对于最流行的shell),同时避免明显不必要的转义,应该转义哪组字符?

最好将整个内容放在单引号中,而不是在单个字符中添加反斜杠;那么您需要转义的唯一字符就是字符串中的一个单引号

作为一个示例,可以很容易地用只有基本原语的任何其他语言重新实现,如下所示:

def quote(s):
    """Return a shell-escaped version of the string *s*."""
    if not s:
        return "''"
    if _find_unsafe(s) is None:
        return s

    # use single quotes, and put single quotes into double quotes
    # the string $'b is then quoted as '$'"'"'b'
    return "'" + s.replace("'", "'\"'\"'") + "'"
也就是说,一般算法如下:

def quote(s):
    """Return a shell-escaped version of the string *s*."""
    if not s:
        return "''"
    if _find_unsafe(s) is None:
        return s

    # use single quotes, and put single quotes into double quotes
    # the string $'b is then quoted as '$'"'"'b'
    return "'" + s.replace("'", "'\"'\"'") + "'"
  • 空字符串变为
    '
    (一对文字单引号)
  • 一个已知是安全的字符串(尽管根本不尝试实现代码路径是最安全的,特别是当Shell通常在未定义的空间中实现自己的语法扩展时)可以无引号/无引号地发出
  • 否则,在
    '
    前面加上一个
    '
    ,发出输入字符串,将所有
    '
    替换为文本字符串
    '“
    ”,然后附加最后一个
    '

就这样。您不需要转义反斜杠(它们在单引号中是文字)、换行符(类似地)或其他任何内容。

对于记录,
Terminal.app在将文件名放入其窗口时转义以下非控制ASCII字符:

空间

!!“#$%&'()*,:;?[]`{124;}~

这些都没有逃脱:

控制代码(00-1F和7F)

字母数字

+-@^_

下面是执行替换的代码:

NSString*shellPathFromPOSIXPath(NSString*path)
{
静态NSRegularExpression*regex=nil;
if(!regex){
NSString*模式=
@"([ !\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\,\\:\\;\\\\?\\[\\]\\`\\{\\|\\}\\~])";
正则表达式=
[NSRegularExpression regular expression with pattern:pattern options:0错误:无];
}
NSString*结果=
[正则表达式StringByRePlacingMatchesInstalling:路径
选项:0
范围:NSMakeRange(0,路径长度)
withTemplate:@“\\$1”];
返回结果;
}

如果这是一个快速问题,则应将其标记为快速问题。关于如何在bash中实现这一点,最好的答案是让shell本身为您进行转义:
printf'%q\n'$name'
,也就是说,如果您想要一个简短、可读且功能强大的引用实现,那么在这里做得很好。需要注意的是,它不能保证输出仅为ASCII可读/可见字符;如果您试图引用带有tabs/newlines/BELs/etc的内容,您会得到tabs/newlines/BELs/etc,只是在引号中,这样符合POSIX的shell就会将它们视为文字……当然,您也可以将shell作为子进程进行派生
execlp(“bash”、“bash”、“-c”、“printf“%q”\“$1\”、“\u0”、myStringVar,NULL)
是c中的样子(输出写入stdout并能够从中捕获),这将使您只使用可打印的ASCII字符获得一个7位干净的结果(虽然不能保证所有POSIX外壳都支持;<代码> $'/COD>是一个KSH和BASH ISM,它可能在以后的标准中,但是还没有。如果你想要万无一失的话,它也取决于你真正要粘贴的东西。考虑文件名“-RQ”。。完全合法,不需要任何转义,但粘贴到某些命令行(前缀为“/”或“\\”,以确保安全,具体取决于您的操作系统)非常糟糕。如果要粘贴到shell中,您需要担心的是shell解析器,而不是目标程序,因此(1)通配符,(2)空格(3)重定向和进程控制,(4)引号和转义符。即,“*?()|$$,等等。如果您要传递到argv数组中的另一个应用程序,则不需要转义,除非它有问题。感谢您的努力。但这不是我所要求的。我确实需要不带引号的字符串,因为我不想在此讨论的原因。我添加了objc和swift标记,以便更清楚地说明我不需要Python解决方案(除非它会调用CF框架)。Python解决方案的要点是为您提供一个可以用您选择的任何语言实现的算法(因为您最初没有标记任何实现语言)。坦率地说,如果你想得到一个真正正确的答案,你需要了解为什么引号是不可接受的;许多使引号明显中断的情况也会使反斜杠以不明显的方式中断(shell命令行解析器如何解释反斜杠取决于上下文)因此,如果你不透露细节,你很可能会得到一个有细微错误的答案。(注意,在shell中,引用是一个按字符的字符;你是否认为一个“引用的”字符串当且仅当它完全是引号的时候?<代码> fo ' bar < /COD>解析为与“代码> Foo\Bar 完全相同的字符串”。.我再次更新了我的问题,现在只需要问n