是否可以在命令行中用perl获取printf格式的特定参数?

是否可以在命令行中用perl获取printf格式的特定参数?,perl,arguments,printf,Perl,Arguments,Printf,需要构建一个字符串foobar不是foo,也不是bar 在printf格式%$2s中,“2”表示特定的参数位置 但它在perl中不起作用: $ perl -e "printf('%$1s$2s is not %$1s and not %$2s', 'foo', 'bar');" %2 is not %1 and not %2 我的环境: $ perl --version This is perl 5, version 16, subversion 3 (v5.16.3) built for

需要构建一个字符串
foobar不是foo,也不是bar

printf
格式
%$2s
中,“2”表示特定的参数位置

但它在perl中不起作用:

$ perl -e "printf('%$1s$2s is not %$1s and not %$2s', 'foo', 'bar');"
%2 is not %1 and not %2
我的环境:

$ perl --version

This is perl 5, version 16, subversion 3 (v5.16.3) built for x86_64-linux-thread-multi
(with 29 registered patches, see perl -V for more detail)

这在*尼克斯对我有效:

perl -e "printf('%s%s is not %1\$s and not %2\$s', 'foo', 'bar');"
请参阅,特别是最后的示例:

这里还有一些例子;请注意,使用显式索引时,
$
可能需要转义:

printf "%2\$d %d\n",      12, 34;     # will print "34 12\n"
printf "%2\$d %d %d\n",   12, 34;     # will print "34 12 34\n"
printf "%3\$d %d %d\n",   12, 34, 56; # will print "56 12 34\n"
printf "%2\$*3\$d %d\n",  12, 34,  3; # will print " 34 12\n"
printf "%*1\$.*f\n",       4,  5, 10; # will print "5.0000\n"

这在*尼克斯对我有效:

perl -e "printf('%s%s is not %1\$s and not %2\$s', 'foo', 'bar');"
请参阅,特别是最后的示例:

这里还有一些例子;请注意,使用显式索引时,
$
可能需要转义:

printf "%2\$d %d\n",      12, 34;     # will print "34 12\n"
printf "%2\$d %d %d\n",   12, 34;     # will print "34 12 34\n"
printf "%3\$d %d %d\n",   12, 34, 56; # will print "56 12 34\n"
printf "%2\$*3\$d %d\n",  12, 34,  3; # will print " 34 12\n"
printf "%*1\$.*f\n",       4,  5, 10; # will print "5.0000\n"
你的报价被取消了

perl -E 'say sprintf(q{%1$s%2$s is not %1$s and not %2$s}, "foo", "bar");'
foobar is not foo and not bar
您不能对
-e
使用双引号
,因为shell会混淆。你需要单引号。但是如果对
%1$s
语法的
printf
模式使用双引号,Perl将尝试插入
$s
,这是不起作用的。因此,请使用非引号
q{}
或将单引号
'
转义为
\'
。或者退出
$
s

如果启用
使用严格
使用警告
,您将看到:

$ perl -E 'use strict; use warnings; say sprintf("%1$s%2$s is not %1$s and not %2$s", "foo", "bar");'
Global symbol "$s" requires explicit package name at -e line 1.
Global symbol "$s" requires explicit package name at -e line 1.
Global symbol "$s" requires explicit package name at -e line 1.
Global symbol "$s" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
这是用单引号
'
表示
-e
,双引号
'
表示模式

$ perl -E "use strict; use warnings; say sprintf('%1$s%2$s is not %1$s and not %2$s', 'foo', 'bar');"
Invalid conversion in sprintf: "%1 " at -e line 1.
Invalid conversion in sprintf: "%2" at -e line 1.
%2 is not %1 and not %2
现在,由于双引号
,shell尝试插入
$s
。所以Perl从来没有看到过它。它将模式视为
“%1%2不是%1,也不是%2”
,它无法理解。(请注意,
%
在Perl中不会在双引号字符串中插入)。

您的引号已关闭

perl -E 'say sprintf(q{%1$s%2$s is not %1$s and not %2$s}, "foo", "bar");'
foobar is not foo and not bar
您不能对
-e
使用双引号
,因为shell会混淆。你需要单引号。但是如果对
%1$s
语法的
printf
模式使用双引号,Perl将尝试插入
$s
,这是不起作用的。因此,请使用非引号
q{}
或将单引号
'
转义为
\'
。或者退出
$
s

如果启用
使用严格
使用警告
,您将看到:

$ perl -E 'use strict; use warnings; say sprintf("%1$s%2$s is not %1$s and not %2$s", "foo", "bar");'
Global symbol "$s" requires explicit package name at -e line 1.
Global symbol "$s" requires explicit package name at -e line 1.
Global symbol "$s" requires explicit package name at -e line 1.
Global symbol "$s" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
这是用单引号
'
表示
-e
,双引号
'
表示模式

$ perl -E "use strict; use warnings; say sprintf('%1$s%2$s is not %1$s and not %2$s', 'foo', 'bar');"
Invalid conversion in sprintf: "%1 " at -e line 1.
Invalid conversion in sprintf: "%2" at -e line 1.
%2 is not %1 and not %2

现在,由于双引号
,shell尝试插入
$s
。所以Perl从来没有看到过它。它将模式视为
“%1%2不是%1,也不是%2”
,它无法理解。(请注意,
%
在Perl中不会以双引号字符串插入)。

让我们看看传递给
Perl的程序:

$ printf '%s' "printf('%$1s$2s is not %$1s and not %$2s', 'foo', 'bar');"
printf('%ss is not %s and not %s', 'foo', 'bar');
正如您所看到的,您的程序中没有
$1
$2
,因为您不正确地构建了shell命令。就像Perl在双引号中插入一样,
sh
和相关shell也是如此。你应该使用单引号

perl -e'printf("%\$1s\$2s is not %\$1s and not %\$2s\n", "foo", "bar");'

(我建议在Perl程序中从
'
切换到
q{}
,这样您就不必避开美元符号,但是您仍然需要对缺少的
\n
使用双引号。)

让我们看看您传递给
Perl
的程序:

$ printf '%s' "printf('%$1s$2s is not %$1s and not %$2s', 'foo', 'bar');"
printf('%ss is not %s and not %s', 'foo', 'bar');
正如您所看到的,您的程序中没有
$1
$2
,因为您不正确地构建了shell命令。就像Perl在双引号中插入一样,
sh
和相关shell也是如此。你应该使用单引号

perl -e'printf("%\$1s\$2s is not %\$1s and not %\$2s\n", "foo", "bar");'

(我会建议在Perl程序中从
'
切换到
q{}
,这样就不必避开美元符号,但是你需要为你丢失的
\n
加双引号。)

@Huntermillen,你的意思是要创建一个函数吗
perl-e“sub-ppp(){printf(“%1$s%2$s不是%1$s,也不是%2$s”,“foo”,“bar”);}ppp();”
像这样吗?。。这不起作用。@HunterMcMillen,你的意思是创建函数吗
perl-e“sub-ppp(){printf(“%1$s%2$s不是%1$s,也不是%2$s”,“foo”,“bar”);}ppp();”
像这样吗?。。这不行,我明白了,谢谢!有点不清楚,如果我使用单引号,为什么会导致错误:
perl-E'use strict;使用警告;比如sprintf(\'%1$s%2$s不是%1$s,也不是%2$s\'、\'foo\'、\'bar\');'。错误:
bash:unexpected token')附近的语法错误。
@Kirby这是个好问题。如果删除括号
(您不需要它们),它只需要更多的输入,而不会运行您的程序。我不知道它不喜欢什么。但是,引用和转义shell是很棘手的。我的建议是对模式使用
q{}
,对args使用您喜欢的任何东西。我会做
printfq{%1$d..},qw(foobar)
所以我根本不需要处理引号请注意,使用
-E
是不向前兼容的,这意味着升级Perl可能会破坏程序。我建议不要使用它,除了一次性的程序。您可以使用
-e
+
CORE::say
而不是
-e
+
say
@ikegami是正确的。我用它来获得
,这样我就有了一条新的线路。对于解释,不管你是使用
-e
还是
-e
,我都明白了,谢谢!有点不清楚,如果我使用单引号,为什么会导致错误:
perl-E'use strict;使用警告;比如sprintf(\'%1$s%2$s不是%1$s,也不是%2$s\'、\'foo\'、\'bar\');'。错误:
bash:unexpected token')附近的语法错误。
@Kirby这是个好问题。如果删除括号
(您不需要它们),它只需要更多的输入,而不会运行您的程序。我不知道它不喜欢什么。但是,引用和转义shell是很棘手的。我的建议是对模式使用
q{}
,然后呢