Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何将popen与包含单引号和双引号的命令行参数一起使用?_Python_Bash_Escaping_Popen_Quote - Fatal编程技术网

Python 如何将popen与包含单引号和双引号的命令行参数一起使用?

Python 如何将popen与包含单引号和双引号的命令行参数一起使用?,python,bash,escaping,popen,quote,Python,Bash,Escaping,Popen,Quote,我想在python3中使用subprocess.Popen()运行以下jq命令 $ jq 'INDEX(.images[]; .id) as $imgs | { "filename_with_label":[ .annotations[] | select(.attributes.type=="letter" ) | $imgs[.image_id] + {label:.text} | {id:.id} + {filen

我想在python3中使用
subprocess.Popen()
运行以下
jq
命令

$ jq  'INDEX(.images[]; .id) as $imgs | {
    "filename_with_label":[
         .annotations[]
        | select(.attributes.type=="letter" )
        | $imgs[.image_id] + {label:.text}
        | {id:.id} + {filename:.file_name} + {label:.label}
     ]
   }' image_data_annotation.json > image_data_annotation_with_label.json
请注意,第一个命令行参数包含点、美元符号、单引号内的双引号。 仅供参考,
jq
是用于处理JSON文件的JSON处理器实用程序

我编写了以下python3脚本,用于使用
jq
实用程序自动化JSON文件处理

#!python3
# file name: letter_image_tool.py

import os, subprocess

"""
command line example to automate
$ jq  'INDEX(.images[]; .id) as $imgs | {
    "filename_with_label":[
         .annotations[]
        | select(.attributes.type=="letter" )
        | $imgs[.image_id] + {label:.text}
        | {id:.id} + {filename:.file_name} + {label:.label}
     ]
   }' image_data_annotation.json > image_data_annotation_with_label.json
"""

# define first command line argument
jq_filter='\'INDEX(.images[]; .id) as $imgs | { "filename_with_label" : [ .annotations[] | select(.attributes.type=="letter" ) | $imgs[.image_id] + {label:.text} | {id:.id} + {filename:.file_name} + {label:.label} ] }\''

input_json_files= [ "image_data_annotation.json"]
output_json_files= []

for input_json in input_json_files:
    print("Processing %s" %(input_json))
    filename, ext = os.path.splitext(input_json)
    output_json = filename + "_with_label" + ext
    output_json_files.append(output_json)
    print("output file is : %s" %(output_json))

    #jq_command ='jq' + " " +  jq_filter, input_json + ' > ' +  output_json
    jq_command =['jq', jq_filter,  input_json + ' > ' +  output_json]
    print(jq_command)
    subprocess.Popen(jq_command, shell=True)
在bash上运行上述python脚本将导致以下结果:

$ ./letter_image_tool.py
Processing image_data_annotation.json
output file is : image_data_annotation_with_label.json
['jq', '\'INDEX(.images[]; .id) as $imgs | { "filename_with_label" : [ .annotations[] | select(.attributes.type=="letter" ) | $imgs[.image_id] + {label:.text} | {id:.id} + {filename:.file_name} + {label:.label} ] }\'', 'image_data_annotation.json > image_data_annotation_with_label.json']
jq - commandline JSON processor [version 1.6-124-gccc79e5-dirty]

Usage:  jq [options] <jq filter> [file...]
        jq [options] --args <jq filter> [strings...]
        jq [options] --jsonargs <jq filter> [JSON_TEXTS...]

jq is a tool for processing JSON inputs, applying the given filter to
its JSON text inputs and producing the filter's results as JSON on
standard output.

The simplest filter is ., which copies jq's input to its output
unmodified (except for formatting, but note that IEEE754 is used
for number representation internally, with all that that implies).

For more advanced filters see the jq(1) manpage ("man jq")
and/or https://stedolan.github.io/jq

Example:

        $ echo '{"foo": 0}' | jq .
        {
                "foo": 0
        }

For a listing of options, use jq --help.
第一个参数应该用单引号括起来,如上所述,但我的脚本不处理它

我认为主要问题与第一个命令行参数中使用的点、美元符号、单引号和双引号有关(
jq\u filter
,在上面的python脚本中)。但我不知道如何处理这种与bash相关的复杂元角色

我应该如何解决上述问题

谢谢你的阅读

使用我的解决方案更新

jq_过滤器定义的三重引号,以及如下所示的空间分隔连接

#!python3
# file name: letter_image_tool.py

import os, subprocess

"""
command line example to automate
$ jq  'INDEX(.images[]; .id) as $imgs | {
    "filename_with_label":[
         .annotations[]
        | select(.attributes.type=="letter" )
        | $imgs[.image_id] + {label:.text}
        | {id:.id} + {filename:.file_name} + {label:.label}
     ]
   }' image_data_annotation.json > image_data_annotation_with_label.json
"""

# define first command line argument with triple quotes
jq_filter=""" 'INDEX(.images[]; .id) as $imgs | { 
       "filename_with_label" : [ 
        .annotations[] 
       | select(.attributes.type=="letter" ) 
       | $imgs[.image_id] + {label:.text} 
       | {id:.id} + {filename:.file_name} + {label:.label} ] } ' """

input_json_files= [ "image_data_annotation.json"]
output_json_files= []

for input_json in input_json_files:
    print("Processing %s" %(input_json))
    filename, ext = os.path.splitext(input_json)
    output_json = filename + "_with_label" + ext
    output_json_files.append(output_json)
    print("output file is : %s" %(output_json))

    #jq_command ='jq' + " " +  jq_filter, input_json + ' > ' +  output_json
    # jq command composed with space separated join
    jq_command =' '.join['jq', jq_filter,  input_json, ' > ',  output_json]
    print(jq_command)

    # shell keyword argument should be set True
    subprocess.Popen(jq_command, shell=True)

使用三重双引号,jq_过滤器可以使用多行定义而不是单行定义更具可读性。

需要单引号的原因是为了防止shell对参数进行任何扩展。只有在使用
shell=True
时,这才是一个问题。如果未设置此选项,shell将永远不会触及您的参数,并且不需要“保护”它们

但是,shell还负责
stdout
重定向(即
[…'>',output_json]
)。如果不使用shell,则需要在Python代码中处理重定向。不过,这很简单,只需将参数
stdout=…
添加到
Popen

总而言之,这意味着您的代码可以重写为

import os
import subprocess

# Still define first command line argument with triple quotes for readability
# Note that there are no single quotes though
jq_filter = """INDEX(.images[]; .id) as $imgs | {
       "filename_with_label" : [
        .annotations[]
       | select(.attributes.type=="letter" )
       | $imgs[.image_id] + {label:.text}
       | {id:.id} + {filename:.file_name} + {label:.label} ] }"""

input_json_files = ["image_data_annotation.json"]
output_json_files = []

for input_json in input_json_files:
    print("Processing %s" % (input_json))
    filename, ext = os.path.splitext(input_json)
    output_json = filename + "_with_label" + ext
    output_json_files.append(output_json)
    print("output file is : %s" % (output_json))

    # Keep command as list, since this is what we need when NOT using shell=True
    # Note also that the redirect and the output file are not parts of the argument list
    jq_command = ['jq', jq_filter,  input_json]

    # shell keyword argument should NOT be set True
    # Instead redirect stdout to an out_file
    # (We must open the file for writing before redirecting)
    with open(output_json, "w") as out_file:
        subprocess.Popen(jq_command, stdout=out_file)

通常,建议无论如何不要使用
shell=True
,因为这会打开另一个针对代码的攻击向量,因为注入攻击可以完全访问shell。另外,不使用shell的另一个小好处是,它将减少创建的子进程的数量,因为不需要额外的shell进程。

如果不将命令括在单引号中(在Python脚本中),会发生什么?@JohanL,感谢您的关注,jq命令要求在单引号内包含筛选器定义。以上运行结果来自未处理的单报价问题。我找到了解决方案。使用jq_过滤器定义,在三个双引号中使用单引号,并使用空格join delmiter将单引号保留在命令行上。请参阅更新我的解决方案。我通过反复试验找到了解决办法。因此,如果有人有更优雅的解决方案,请告诉我。ThanksIt按预期工作。谢谢你的解释。
import os
import subprocess

# Still define first command line argument with triple quotes for readability
# Note that there are no single quotes though
jq_filter = """INDEX(.images[]; .id) as $imgs | {
       "filename_with_label" : [
        .annotations[]
       | select(.attributes.type=="letter" )
       | $imgs[.image_id] + {label:.text}
       | {id:.id} + {filename:.file_name} + {label:.label} ] }"""

input_json_files = ["image_data_annotation.json"]
output_json_files = []

for input_json in input_json_files:
    print("Processing %s" % (input_json))
    filename, ext = os.path.splitext(input_json)
    output_json = filename + "_with_label" + ext
    output_json_files.append(output_json)
    print("output file is : %s" % (output_json))

    # Keep command as list, since this is what we need when NOT using shell=True
    # Note also that the redirect and the output file are not parts of the argument list
    jq_command = ['jq', jq_filter,  input_json]

    # shell keyword argument should NOT be set True
    # Instead redirect stdout to an out_file
    # (We must open the file for writing before redirecting)
    with open(output_json, "w") as out_file:
        subprocess.Popen(jq_command, stdout=out_file)