我有一个json,它是一个对象数组 以下代码可以正常工作:
use JSON qw( decode_json );
# the contents of json are from the file jsonfile.json
my $data='[{...}]'; # omitted for clarity
@decoded = @{decode_json($data)};
print Dumper \@decoded;
但是当我尝试从命令行运行它作为单行程时它会中断
以下工作均无效:
cat jsonfile.json | perl -MData::Dumper -MJSON=decode_json -ne'my $data=q{$_}; print decode_json($data)'
cat jsonfile.json | perl -MData::Dumper -MJSON=decode_json -ne"print decode_json('$_')"
我认为问题在于引用。我在脚本中遇到了同样的问题,直到我将qw
替换为’
,否则会引起注意,例如如果@
在字段中,或者它与json字段的双引号混淆。
我在这里做错了什么?
另一个例子:
这打破了:
$ echo [{"a":"b"}] |perl -MData::Dumper -MJSON=decode_json -ne'print decode_json($_)'
unexpected end of string while parsing JSON string, at character offset 3 (before ":b}]\n") at -e line 1.
但这有效:
$ echo '[{"a":"b"}]'| perl -MData::Dumper -MJSON=decode_json -ne'print decode_json($_)'
ARRAY(0x7fd8d400b2b8)
答案 0 :(得分:2)
Bash有许多不同的引用模式:
在单引号'...'
内没有任何内容展开。没有逃脱可用。因此,在这些引号中,您可以使用$variables
而不将它们扩展为Bash变量。这对于Perl单行程来说是理想的。但是你不能在该字符串中使用单引号。因此,Perl单行应该更喜欢在Perl代码中引用q(...)
之类的运算符。
"..."
内的扩展了变量,并且可以转义特殊字符。这对于Perl one-liners来说是不可取的。
Bash有这些引用模式但不是字符串。您可以在一个单词内切换引用模式,因此命令行参数foo"bar"baz'qux'
等于foobarbazqux
。
当我们查看您的JSON代码段时:
echo [{"a":"b"}]
等于echo '[{a:b}]'
,因为"
引号被删除。这不是有效的JSON。echo '[{"a":"b"}]'
按预期工作,因为双引号受单引号保护。在你的Perl oneliners中:
-ne"print decode_json('$_')"
是双引号字符串。 Bash变量$_
扩展为上一个命令的最后一个参数。所以我们实际上传递了类似参数"-neprint decode_json('RANDOM GARBAGE')"
。
-ne'my $data=q{$_}; print decode_json($data)'
被正确转义。
您的初始Perl单行都使用$_
变量周围的单引号:'$_'
和q{$_}
。 Perl不会将变量插入到单引号字符串中,因此您使用的是文字字符串$_
,而不是$_
变量的值。在这些情况下,不需要引号。如果必须使用引号,则最好使用双引号字符串qq{$_}
。
将所有这些放在一起,这样的命令应该有效:
$ perl -MJSON=decode_json -ne'print decode_json($_)' jsonfile.json
但请注意,由于-n
标志,这会逐行读取文件,即每行需要一个JSON文档。
答案 1 :(得分:1)
Perl的-n
选项“导致Perl假定你的程序有以下循环,这使得它迭代文件名参数,有点像sed -n或awk:
LINE:
while (<>) {
... # your program goes here
}
“(来源:https://perldoc.perl.org/perlrun.html)
<>
是perl的输入运算符,在这种情况下称为没有文件句柄,因此它从STDIN读取。 Perl自动拆分输入,默认是拆分换行符(\n
)。这意味着,每个输入行执行一次表达式。除非您的JSON文件包含一行中的所有内容,否则您的代码将无效!
Perl的特殊变量$/
(又名$INPUT_RECORD_SEPARATOR
)控制perl在使用<>
进行阅读时如何拆分多行输入。默认值为\n
,因此每行都会单独读取。通过将其设置为undef
,perl一次性读取整个输入(无论是单行还是多行),在$data
中为您提供文件的完整内容。
您还需要从perl的参数中删除-n
并从STDIN手动读取。
cat jsonfile.json | perl -MData::Dumper -MJSON=decode_json -e '$/=undef; my $data=<>; print decode_json($data)'
$/=undef;
告诉perl不要将输入拆分为单独的行。
my $data=<>;
从STDIN读取。当我们告诉perl不分割输入时,整个输入(文件的完整内容)存储在$data
中。
作为辅助节点:您的代码my $data=q{$_};
无法达到您的预期效果:q{}
相当于单引号('
),因此$data
包含文字字符串$_
(后跟下划线的美元符号),而不是变量$_
的内容。