bash 的 printf %q 是否有任何 csh 替代方案?
Is there any csh alternative for printf %q of bash?
Bash 的内置命令 printf
支持 %q 格式字符串,它转义 shell 输入的变量内容。
我尝试了一些选项::q
只转义space,gnu printf不支持%q
。
目前,我使用以下代码:
set valq = `echo $val:q | bash -c 'read q;printf %q "$q"'`
/path/to/executable $valq
我不喜欢依赖 bash 的 csh 脚本。是否有任何 csh 本机解决方案?
谢谢。
这是一个测试代码,用于说明我遇到的问题。
wrapper.csh
#!/bin/csh -f
set i = 1
set tst1 = ""
set tst2 = ""
while ( $i <= $#argv )
set arg = "$argv[$i]"
set tst1 = ($tst1:q $arg:q)
set arg2 = `echo $arg:q | bash -c 'read q;printf %q "$q"'`
set tst2 = "$tst2:q $arg2:q"
@ i = $i + 1
end
echo "====case 1===="
./test.csh $tst1:q
./test.csh $tst1
./test.csh $tst2
echo "====case 2===="
csh -cf "./test.csh $tst1"
csh -cf "./test.csh $tst1:q"
csh -cf "./test.csh $tst2"
test.csh
#!/bin/csh -f
echo -n "TEST ARG:"
set i = 1
while ($i <= $#argv)
echo -n "${i}:$argv[$i] "
@ i = $i + 1
end
echo
测试结果1:
>./wrapper.csh "a ()" b c
====case 1====
TEST ARG:1:a () 2:b 3:c
TEST ARG:1:a 2:() 3:b 4:c
TEST ARG:1:a\ 2:\(\) 3:b 4:c
====case 2====
Badly placed ()'s.
Badly placed ()'s.
TEST ARG:1:a () 2:b 3:c
测试结果2:
bash>./wrapper.csh "'\"a ()" b c
csh>./wrapper.csh "'"'"'"a ( ) " b c
====case 1====
TEST ARG:1:'"a () 2:b 3:c
TEST ARG:1:'"a 2:() 3:b 4:c
TEST ARG:1:\'\"a\ 2:\(\) 3:b 4:c
====case 2====
Unmatched '.
Unmatched '.
TEST ARG:1:'"a () 2:b 3:c
测试总结:
如果在csh中直接调用命令,那么$val:q
才是正确的用法。
如果命令通过参数传递,那么 printf %q
是正确的用法。
只需使用/path/to/executable "$val"
.
更新
如果在"
(如csh -cf "test.csh $tst1"
)中扩展变量,并且要保留特殊字符和多个单词,则必须确实引用这些单词。但是 bash
的特殊 printf
并不是必不可少的;我们可以做到G。与:
set tst1q=`printf " '%s'" $tst1:q`
csh -cf "test.csh $tst1q"
(没有%q
的正常printf
)。
更新
要同时允许 "
和 '
,您可以在最初执行
set s='s/[] "$&-*;<>?`|~[]/\&/g'
将 bash -c 'read q;printf %q "$q"'
替换为 wrapper.csh
中的 sed "$s"
。
正则表达式
[] "$&-*;<>?`|~[]
是一个括号表达式,[]
括起来的字符列表。它匹配单个字符,该字符将通过替换 \&
加上反斜杠作为前缀(特殊字符 &
指的是匹配的字符)。我没有包含字符 ,
和 ^
(它们被 printf %q
转义,但在 csh
中不需要),而我包含了 ~
(它没有被 printf %q
转义,但需要在 csh
中 - 尝试 wrapper.csh "~"
).
Bash 的内置命令 printf
支持 %q 格式字符串,它转义 shell 输入的变量内容。
我尝试了一些选项::q
只转义space,gnu printf不支持%q
。
目前,我使用以下代码:
set valq = `echo $val:q | bash -c 'read q;printf %q "$q"'`
/path/to/executable $valq
我不喜欢依赖 bash 的 csh 脚本。是否有任何 csh 本机解决方案?
谢谢。
这是一个测试代码,用于说明我遇到的问题。
wrapper.csh
#!/bin/csh -f
set i = 1
set tst1 = ""
set tst2 = ""
while ( $i <= $#argv )
set arg = "$argv[$i]"
set tst1 = ($tst1:q $arg:q)
set arg2 = `echo $arg:q | bash -c 'read q;printf %q "$q"'`
set tst2 = "$tst2:q $arg2:q"
@ i = $i + 1
end
echo "====case 1===="
./test.csh $tst1:q
./test.csh $tst1
./test.csh $tst2
echo "====case 2===="
csh -cf "./test.csh $tst1"
csh -cf "./test.csh $tst1:q"
csh -cf "./test.csh $tst2"
test.csh
#!/bin/csh -f
echo -n "TEST ARG:"
set i = 1
while ($i <= $#argv)
echo -n "${i}:$argv[$i] "
@ i = $i + 1
end
echo
测试结果1:
>./wrapper.csh "a ()" b c
====case 1====
TEST ARG:1:a () 2:b 3:c
TEST ARG:1:a 2:() 3:b 4:c
TEST ARG:1:a\ 2:\(\) 3:b 4:c
====case 2====
Badly placed ()'s.
Badly placed ()'s.
TEST ARG:1:a () 2:b 3:c
测试结果2:
bash>./wrapper.csh "'\"a ()" b c
csh>./wrapper.csh "'"'"'"a ( ) " b c
====case 1====
TEST ARG:1:'"a () 2:b 3:c
TEST ARG:1:'"a 2:() 3:b 4:c
TEST ARG:1:\'\"a\ 2:\(\) 3:b 4:c
====case 2====
Unmatched '.
Unmatched '.
TEST ARG:1:'"a () 2:b 3:c
测试总结:
如果在csh中直接调用命令,那么
$val:q
才是正确的用法。如果命令通过参数传递,那么
printf %q
是正确的用法。
只需使用/path/to/executable "$val"
.
更新
如果在"
(如csh -cf "test.csh $tst1"
)中扩展变量,并且要保留特殊字符和多个单词,则必须确实引用这些单词。但是 bash
的特殊 printf
并不是必不可少的;我们可以做到G。与:
set tst1q=`printf " '%s'" $tst1:q`
csh -cf "test.csh $tst1q"
(没有%q
的正常printf
)。
更新
要同时允许 "
和 '
,您可以在最初执行
set s='s/[] "$&-*;<>?`|~[]/\&/g'
将 bash -c 'read q;printf %q "$q"'
替换为 wrapper.csh
中的 sed "$s"
。
正则表达式
[] "$&-*;<>?`|~[]
是一个括号表达式,[]
括起来的字符列表。它匹配单个字符,该字符将通过替换 \&
加上反斜杠作为前缀(特殊字符 &
指的是匹配的字符)。我没有包含字符 ,
和 ^
(它们被 printf %q
转义,但在 csh
中不需要),而我包含了 ~
(它没有被 printf %q
转义,但需要在 csh
中 - 尝试 wrapper.csh "~"
).