在打印传递给 bash 函数的所有参数时如何明确引用?但是要注意引用特殊字符,避免使用反斜杠?

How to unambiguously quote when printing all args passed to a bash function? But taking care to quote special characters, avoid using the backslash?

提问人:NevilleDNZ 提问时间:7/11/2023 最后编辑:NevilleDNZ 更新时间:7/11/2023 访问量:51

问:

基本上,我需要一个名为 echo_Q(或选项)的 shell 函数,而不是回显带引号的参数列表,同时“[nicely]”如果可能的话,严格避免对任何参数进行任何反斜杠引用。echo -Q

带有一些问题参数的本机的原始示例:echo

echo another_script a "b b" "c 'c' c" 'd "d" d' "e "'"'"'e'"'"'" e" "ls -ltrd .??* | sort -k5,5 > f.lst" 'file `ls -t $HOME`' '|' '&' ';' "<"

自然,本地产品:echo

another_script a b b c 'c' c d "d" d e "'e'" e ls -ltrd .??* | sort -k5,5 > f.lst file `ls -t $HOME` | & ; <

在上面的结果中:已经评估了报价,其中必要的空格和报价变得不透明。

我试过了,甚至:printf " %q" "$@"; echo

echo_q(){
    sep="";
    for arg in "$@"; do
        printf "$sep%q" "$arg"
        sep=" "
    done
    echo
}

并获得完全“转义”(冗长)的输出,其中完全避免引用。

echo_q another_script a "b b" etc..

another_script a b\ b c\ \'c\'\ c d\ \"d\"\ d e\ \"\'e\'\"\ e ls\ -ltrd\ .\?\?\*\ \|\ sort\ -k5\,5\ \>\ f.lst file\ \`ls\ -t\ \$HOME\` \| \& \; \>

在上面的结果中:从技术上讲,输出是我想要的,但由于所有的反斜杠,读起来有点“不愉快”。

我更喜欢(为了可读性)以下输出:

another_script a 'b b' "c 'c' c" 'd "d" d' e\ \"\'e\'\"\ e 'ls -ltrd .??* | sort -k5,5 > f.lst' 'file `ls -t $HOME`' '|' '&' ';' '>'

这是我一直在涉足的一个“简单”的黑客

special='$( )*?`<>\\|&;'
qq_special='$`'

echo_Q(){
    sep="";
    for arg in "$@"; do
        printf "$sep";
        sep=" "
        case "$arg" in
        (*["$special'"'"']*)
            case "$arg" in
            (*'"'*)
                case "$arg" in
                    (*"'"*)printf "%q" "$arg";;
                    (*)printf "'%s'" "$arg";;
                esac;;
            (*"'"*)
                case "$arg" in
                    (*"$qq_special"*) printf "%q" "$arg";;
                    (*) printf '"%s"' "$arg";;
                esac;;
            (*) printf "'%s'" "$arg";;
            esac;;
        (*) printf "%s" "$arg";;
        esac
        sep=" "
    done
    echo
}

但我希望有一种标准(且更简单)的方法来“很好地”函数的参数......echo

Bash 确实有: ,但我需要的是一个很好地引用一个论点。可悲的是,如此简单的事情让我难以理解。:-(printf "%q"printf "%Q"

欢迎提示!

bash 转义 echo 特殊字符 引号

评论

0赞 Inian 7/11/2023
你正在处理的确切输入词集是什么?
0赞 NevilleDNZ 7/11/2023
例如。echo_Q another_script a "b b" "c 'c' c" 'd "d" d' "e "'"'"'e'"'"'" e" "ls -ltrd .??* | sort -k5,5 > f.lst" 'file `ls -t $HOME`' '|' '&' ';' "<"
0赞 user1934428 7/11/2023
我认为你需要很好地定义你对这个词的理解。你似乎喜欢引号,但不喜欢反斜杠。但是,您显示为可接受的替代项也包含反斜杠。您似乎在寻找一个非常具体的漂亮打印机来获取变量。也许你只需要实现一个。
0赞 NevilleDNZ 7/11/2023
回复:在最简单的情况下,除非没有其他方法,否则永远不要使用反斜杠。或者,使用单引号 (') 或双引号 (“),除非”反斜杠引号“,否则参数短了 4 个字符。实际上,我希望“引用引用”已经内置到......而我只是没有找到它!;-)def nicely(): ... bash
1赞 Toby Speight 7/11/2023
这里的部分问题在于,“很好”是主观的(因为它需要更多的判断,所以可能比扩展慢)。而“可用作输入”是一个客观的功能规范。printf %q${…@Q}

答:

3赞 Inian 7/11/2023 #1

Bash 确实支持一种以可以重用为输入 agin 的方式引用参数的方法。参数扩展支持标志(在 bash v4.4 中引入)${parameter@operator}

Q 扩展是一个字符串,它是参数的值,以可重用作输入的格式引用。

set -- a "b b" "c 'c' c" 'd "d" d' "e "'"'"'e'"'"'" e" "ls -ltrd .??* | sort -k5,5 > f.lst" 'file `ls -t $HOME`' '|' '&' ';' "<"
for arg in "$@"; do
    printf '%s\n' "${arg@Q}"
done

生产

'a'
'b b'
'c '\''c'\'' c'
'd "d" d'
'e "'\''e'\''" e'
'ls -ltrd .??* | sort -k5,5 > f.lst'
'file `ls -t $HOME`'
'|'
'&'
';'
'<'

评论

4赞 Ivan 7/11/2023
无需循环它,只需执行:对于自定义数组,它将是${@@Q}${arr[@]@Q}
1赞 Inian 7/11/2023
@Ivan 没错,仅用于演示。
0赞 NevilleDNZ 7/11/2023
尼斯:但是你找到“${arg@Q}”了吗?... 和一本150页的平装小说一样大。man bash
3赞 Inian 7/11/2023
@NevilleDNZ - 它来自实践,你需要知道,你在寻找什么 - gnu.org/software/bash/manual/... (在底部)
2赞 Inian 7/11/2023
是的,如前所述,上面的编码方式,在 shell 上下文中再次重用它是安全的。如果你正在寻找一种特定的格式风格,也许重写你自己的引用逻辑应该是方法
0赞 xpusostomos 7/11/2023 #2

我猜你要做的是执行一个带有一些带引号参数的命令,然后以一种看起来不错的方式将其打印出来,包括 bash 风格的引用。上一张海报的解决方案很好,尽管它没有保留你原来的报价。这里有一个小片段,可能对你有一定用处,可以保持它的精确性:

$ read A <<eof
> a "b b" "c 'c' c" 'd "d" d' "e "'"'"'e'"'"'" e"
> eof
$ echo $A
a "b b" "c 'c' c" 'd "d" d' "e "'"'"'e'"'"'" e"
$ eval echo $A
a b b c 'c' c d "d" d e "'e'" e
printx() {
> for i in "$@"
> do
> echo "$i"
> done
> }
$ eval printx $A
a
b b
c 'c' c
d "d" d
e "'e'" e