无法在命令行

时间:2017-12-06 09:56:30

标签: json bash perl

我有一个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)

2 个答案:

答案 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包含文字字符串$_(后跟下划线的美元符号),而不是变量$_的内容。