bash 在shell脚本中读取python变量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34751930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 14:05:53  来源:igfitidea点击:

Read a python variable in a shell script?

pythonbashshell

提问by jxn

my python file has these 2 variables:

我的python文件有这两个变量:

week_date = "01/03/16-01/09/16"
cust_id = "12345"

how can i read this into a shell script that takes in these 2 variables?

我如何将其读入包含这两个变量的 shell 脚本?

my current shell script requires manual editing of "dt" and "id". I want to read the python variables into the shell script so i can just edit my python parameter file and not so many files.

我当前的 shell 脚本需要手动编辑“dt”和“id”。我想将 python 变量读入 shell 脚本,这样我就可以编辑我的 python 参数文件而不是那么多文件。

shell file:

外壳文件:

#!/bin/sh

dt="01/03/16-01/09/16" 
cust_id="12345"

In a new python file i could just import the parameter python file.

在一个新的 python 文件中,我可以只导入参数 python 文件。

回答by Charles Duffy

Consider something akin to the following:

考虑类似于以下内容:

#!/bin/bash
#      ^^^^ NOT /bin/sh, which doesn't have process substitution available.

python_script='
import sys
d = {}                                    # create a context for variables
exec(open(sys.argv[1], "r").read()) in d  # execute the Python code in that context
for k in sys.argv[2:]:
  print "%s
read_python_vars config.py week_date:dt cust_id:id
echo "Customer id is $id; date range is $dt"
" % str(d[k]).split("
read_python_vars config.py week_date cust_id
echo "Customer id is $cust_id; date range is $week_date"
")[0] # ...and extract your strings NUL-delimited ' read_python_vars() { local python_file=; shift local varname for varname; do IFS= read -r -d '' "${varname#*:}" done < <(python -c "$python_script" "$python_file" "${@%%:*}") }

You might then use this as:

然后,您可以将其用作:

start_date = '01/03/16'
end_date = '01/09/16'
week_date = '%s-%s' % (start_date, end_date)

...or, if you didn't want to rename the variables as they were read, simply:

...或者,如果您不想在读取变量时重命名它们,只需:

start_date = '01/03/16'
end_date = '01/09/16'
week_date = '%s-%s' % (start_date, end_date)


Advantages:

好处:

  • Unlike a naive regex-based solution (which would have trouble with some of the details of Python parsing -- try teaching sedto handle both raw and regular strings, and both single and triple quotes without making it into a hairball!) or a similar approach that used newline-delimited output from the Python subprocess, this will correctly handle any object for which str()gives a representation with no NUL characters that your shell script can use.
  • Running content through the Python interpreter also means you can determine values programmatically -- for instance, you could have some Python code that asks your version control system for the last-change-date of relevant content.

    Think about scenarios such as this one:

    dt="01/03/16-01/09/16"
    cust_id="12345"
    

    ...using a Python interpreter to parse Python means you aren't restricting how people can update/modify your Python config file in the future.

  • 与基于正则表达式的幼稚解决方案(它会在 Python 解析的一些细节上遇到问题——尝试教授sed处理原始字符串和常规字符串,以及单引号和三引号,而不会将其变成毛球!)或类似的方法使用来自 Python 子进程的换行符分隔的输出,这将正确处理任何对象,这些对象str()给出的表示没有您的 shell 脚本可以使用的 NUL 字符。
  • 通过 Python 解释器运行内容还意味着您可以以编程方式确定值——例如,您可以使用一些 Python 代码向您的版本控制系统询问相关内容的最后更改日期。

    想想这样的场景:

    config_vars = {}
    with open('the/file/path', 'r') as f:
        for line in f:
            if '=' in line:
                k,v = line.split('=', 1)
                config_vars[k] = v
    week_date = config_vars['dt']
    cust_id = config_vars['cust_id']
    

    ...使用 Python 解释器来解析 Python 意味着您不会限制人们将来如何更新/修改您的 Python 配置文件。

Now, let's talk caveats:

现在,让我们谈谈警告:

  • If your Python code has side effects, those side effects will obviously take effect (just as they would if you chose to importthe file as a module in Python). Don't use this to extract configuration from a file whose contents you don't trust.
  • Python strings are Pascal-style: They can contain literal NULs. Strings in shell languages are C-style: They're terminated by the first NUL character. Thus, some variables can exist in Python than cannot be represented in shell without nonliteral escaping. To prevent an object whose str()representation contains NULs from spilling forward into other assignments, this code terminates strings at their first NUL.
  • 如果您的 Python 代码有副作用,这些副作用显然会生效(就像您选择import将文件作为 Python 中的模块一样)。不要使用它从您不信任其内容的文件中提取配置。
  • Python 字符串是 Pascal 风格的:它们可以包含文字 NUL。shell 语言中的字符串是 C 风格的:它们以第一个 NUL 字符结尾。因此,某些变量可以存在于 Python 中,而在没有非文字转义的情况下无法在 shell 中表示。为了防止str()表示包含 NUL的对象向前溢出到其他赋值中,此代码在字符串的第一个 NUL 处终止。


Now, let's talk about implementation details.

现在,让我们谈谈实现细节。

  • ${@%%:*}is an expansion of $@which trims all content after and including the first :in each argument, thus passing only the Python variable names to the interpreter. Similarly, ${varname#*:}is an expansion which trims everything up to and including the first :from the variable name passed to read. See the bash-hackers page on parameter expansion.
  • Using <(python ...)is process substitution syntax: The <(...)expression evaluates to a filename which, when read, will provide output of that command. Using < <(...)redirects output from that file, and thus that command (the first <is a redirection, whereas the second is part of the <(token that starts a process substitution). Using this form to get output into a while readloop avoids the bug mentioned in BashFAQ #24 ("I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates? Or, why can't I pipe data to read?").
  • The IFS= read -r -d ''construct has a series of components, each of which makes the behavior of readmore true to the original content:

    • Clearing IFSfor the duration of the command prevents whitespace from being trimmed from the end of the variable's content.
    • Using -rprevents literal backslashes from being consumed by readitself rather than represented in the output.
    • Using -d ''sets the first character of the empty string ''to be the record delimiter. Since C strings are NUL-terminated and the shell uses C strings, that character is a NUL. This ensures that variables' content can contain any non-NUL value, including literal newlines.

    See BashFAQ #001 ("How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?")for more on the process of reading record-oriented data from a string in bash.

回答by viraptor

Other answers give a way to do exactly what you ask for, but I think the idea is a bit crazy. There's a simpler way to satisfy both scripts - move those variables into a config file. You can even preserve the simple assignment format.

其他答案提供了一种完全按照您的要求做的方法,但我认为这个想法有点疯狂。有一种更简单的方法可以满足这两个脚本 - 将这些变量移动到配置文件中。您甚至可以保留简单的分配格式。

Create the config itself: (ini-style)

创建配置本身:(ini 样式)

source "the/file/path"

In python:

在蟒蛇中:

#!/bin/sh
exec <$python_filename
while read line
do
        match=`echo $line|grep "week_date ="`
        if [ $? -eq 0 ]; then
                dt=`echo $line|cut -d '"' -f 2`
        fi

        match=`echo $line|grep "cust_id ="`
        if [ $? -eq 0 ]; then
                cust_id=`echo $line|cut -d '"' -f 2`
        fi
done

In bash:

在 bash 中:

##代码##

And you don't need to do crazy source parsing anymore. Alternatively you can just use json for the config file and then use jsonmodule in python and jqin shell for parsing.

而且您不再需要进行疯狂的源解析。或者,您可以只将 json 用于配置文件,然后json在 python 和jqshell 中使用模块进行解析。

回答by dganesh2002

I would do something like this. You may want to modify it little bit for minor changes to include/exclude quotes as I didn't really tested it for your scenario:

我会做这样的事情。您可能需要稍微修改它以进行细微的更改以包含/排除引号,因为我没有真正针对您的场景测试过它:

##代码##