GVKun编程网logo

从Shell脚本调用Python函数(shell脚本调用python脚本)

20

这篇文章主要围绕从Shell脚本调用Python函数和shell脚本调用python脚本展开,旨在为您提供一份详细的参考资料。我们将全面介绍从Shell脚本调用Python函数的优缺点,解答shell

这篇文章主要围绕从Shell脚本调用Python函数shell脚本调用python脚本展开,旨在为您提供一份详细的参考资料。我们将全面介绍从Shell脚本调用Python函数的优缺点,解答shell脚本调用python脚本的相关问题,同时也会为您带来bash – 如何将stdin从shell脚本重定向到shell脚本中的命令?、bash – 无法从shell脚本调用Openscad -D命令行、bash – 通过sudo – 环境变量从另一个shell脚本调用shell脚本?、go执行python/shell脚本的实用方法。

本文目录一览:

从Shell脚本调用Python函数(shell脚本调用python脚本)

从Shell脚本调用Python函数(shell脚本调用python脚本)

我试图弄清楚如何从Shell脚本调用Python函数。

我有一个具有多个功能的Python文件,我需要在我的shell脚本中使用它们返回的值。有没有办法做到这一点。

我这样做是为了使用Python读取配置文件并在shell中获取值。还有其他更好的方法来实现这一目标。

test.py 包含:

import ConfigParserconfig = ConfigParser.ConfigParser()config.read("test.conf")def get_foo():    return config.get("locations", "foo")def get_bar():    return config.get("locations", "bar")

我需要将Python函数返回的值存储在shell变量中。

答案1

小编典典

您可以通过要求Python解释器打印结果来将函数的结果发送到标准输出:

python -c ''import test; print test.get_foo()''

-c选项只是要求Python执行一些Python命令。

为了将结果存储在变量中,因此可以执行以下操作:

RESULT_FOO=`python -c ''import test; print test.get_foo()''`

或者,等效地

RESULT=$(python -c ''import test; print test.get_foo()'')

自反引号起,并$(…)评估命令并用其输出替换它。

PS :要获取每个功能的结果,都需要使用这种方法每次都解析配置文件。可以通过一次返回所有结果来优化此过程,例如:

ALL_RESULTS=$(python -c ''import test; print test.get_foo(), test.get_bar()'')

然后可以将结果拆分并放入不同的变量中

RESULT_BAR=$(echo $ALL_RESULTS | cut -d'' '' -f2)

它以 第二个 结果并将其放入RESULT_BAR(例如,类似地:-fn对于结果#n)。

PPS :正如Pablo
Maurin提到的那样,如果可能的话,在一个解释器(Python,但也可能在Shell)中完成所有操作可能会更容易,而不是在一个程序中计算变量并在另一个程序中使用它们。

bash – 如何将stdin从shell脚本重定向到shell脚本中的命令?

bash – 如何将stdin从shell脚本重定向到shell脚本中的命令?

如何将stdin从 shell脚本重定向到 shell脚本中的命令?我试图将stdin传递给 java system.in流.

我想替换

find . -type f | $JAVA_HOME/bin/java com.domain.BatchProcess

find . -type f | ./batch.sh

解决方法

如果命令:

$JAVA_HOME/bin/java com.domain.BatchProcess

期待来自stdin的输入,然后将其放入脚本中并运行第二个命令将起作用.

bash – 无法从shell脚本调用Openscad -D命令行

bash – 无法从shell脚本调用Openscad -D命令行

我在Ubuntu linux上使用openscad命令从命令行生成模型.我最终成功运行了openscad命令,使用-D参数覆盖变量值:

$openscad -o output.stl -D 'param1="name1"' -D 'param2="name2"' openscad-script.scad

编辑:注意我们必须传递-D参数的方式,单引号和双引号必须根据因为Openscad documentation.

但当我生成&从shell脚本执行相同的命令,openscad失败并出现错误:

$./myscript.sh value1 value2

ERROR: Parser error in line XX: Syntax error Can’t parse file
‘openscad-script.scad’!

其中XX =文件的最后一行.

这是bash脚本

#!/bin/bash
# run openscad command
param1="-D 'param1=\"$1\"'"
param2="-D 'param2=\"$2\"'"
echo "openscad -o $1-$2.stl $param1 $param2 openscad-script.scad"
openscad -o $1-$2.stl $param1 $param2 openscad-script.scad

这看起来很简单,我仍然无法弄清楚opencad在运行命令时失败的原因.

谢谢你的帮助,

编辑:我发现了一种让它工作的方法,可能不是最好的

#!/bin/bash
# run openscad command
param1="-D 'param1=\"$1\"'"
param2="-D 'param2=\"$2\"'"
command = "openscad -o $1-$2.stl $param1 $param2 openscad-script.scad"
eval $command

解决方法

如果您的命令行是:

openscad -o name1-name2.stl -D 'param1="name1"' -D 'param2="name2"' openscad-script.scad

…然后执行此操作的正确脚本将是:

#!/bin/bash
openscad \
  -o "$1-$2.stl" \
  -D "param1=\"$1\"" \
  -D "param2=\"$2\"" \
  openscad-script.scad

…或者,如果你真的想因为某种原因在多行上建立东西:

#!/bin/bash

args=( -o "$1-$2.stl" )
args+=( -D "param1=\"$1\"" )
args+=( -D "param2=\"$2\"" )

openscad "${args[@]}" openscad-script.scad

openscad字面上无法知道命令行中是否使用了单引号或双引号,因此没有可强制执行的方法来要求单引号.而且,shell引用是逐个字符的属性!也就是说:

'param1="name1"' # becomes the C string "param1=\"name1\""

导致完全相同的字符串传递为:

param1='"name1"' # becomes the C string "param1=\"name1\"",same as above

要么

param1='"'name1'"' # becomes the C string "param1=\"name1\"",same as above

……当这些值都是常数时.但是,当name1被替换为$1之类的东西时,根据使用的引号类型,含义会变得非常不同:

set -- name1; IFS=0123456789
"param1=\"$1\"" # becomes the C string "param1=\"name1\"",as above
'param1="$1"'   # becomes the C string "param1=\"$1\"",not substituting name1

# ...and,as an example of something to look out for:
param1='"'$1'"'  # becomes TWO C strings,"param1=\"name" and "\"",due to bad quoting
# ...the IFS above makes it split on numbers; by default this risk would happen with spaces

bash – 通过sudo – 环境变量从另一个shell脚本调用shell脚本?

bash – 通过sudo – 环境变量从另一个shell脚本调用shell脚本?

我正在从脚本A调用bash脚本B.在脚本A(父脚本)中,我正在导出一些变量.我想在脚本B(下标)中使用这些变量,但是变量值没有从脚本A传递到脚本B.有没有办法从脚本B访问变量值?

#!/bin/bash
# script_A.sh
export VAR="value"
enter code here
sudo -u user ./script_B.sh

#!/bin/bash
# script_B.sh
echo $VAR    # this prints nothing

解决方法

正如@geekosaur所提到的,sudo出于安全原因重置了环境.
为了保护环境,请将-E切换到sudo.

来自sudo手册页:

-E

The -E (preserve environment) option indicates to the security policy that the user wishes to preserve their existing
environment variables. The security policy may return an error if the -E option is specified and the user does not have permission to preserve the environment.

go执行python/shell脚本

go执行python/shell脚本

一、背景

项目的后台是golang, 但是一个子模块是python写好了的,为了能够快速使用上,打算用golang调用python。但是从长远的角度来看,在服务内部,跨语言,跨进程,最好使用RPC的方式。 本文主要讲解如何通过go来调用python脚本或者本地shell脚本,并获取脚本的输出结果。

二、用法

执行python有两种常见的方法:一种是直接执行python,一种是通过执行shell脚本来执行python。

2.1 直接执行python

详见参考2

demo1: 先写好要执行的python文件, fib.py

# fib.py
def fib(n):
    if n <= 2:
        return 1
    return fib(n-1) + fib(n-2)


demo2: 写go,调用python模块以及函数,然后执行

func main() {
	m := python.PyImport_ImportModule("sys")
	if m == nil {
		fmt.Println("import error")
		return
	}
	path := m.GetAttrString("path")
	if path == nil {
		fmt.Println("get path error")
		return
	}
	//加入当前目录,空串表示当前目录
	currentDir := python.PyString_FromString("")
	python.PyList_Insert(path, 0, currentDir)

	m = python.PyImport_ImportModule("fib") //加载python的模块,文件名
	if m == nil {
		fmt.Println("import error")
		return
	}
	fib := m.GetAttrString("fib")//加载python的方法
	if fib == nil {
		fmt.Println("get fib error")
		return
	}
	out := fib.CallFunction(python.PyInt_FromLong(10))//调用python的方法,并传参
	if out == nil {
		fmt.Println("call fib error")
		return
	}
	fmt.Printf("fib(%d)=%d\n", 10, python.PyInt_AsLong(out))
}

异常场景

Package python-2.7 was not found in the pkg-config search path

解决方法:

执行以下命令:

pkg-config --list-all | grep python

如果结果为空,说明包配置里没有python的配置,可以通过以下方式解决:

# centos
yum install python-devel
# ubuntu
apt-get install python-dev

2.2 通过调用shell间接执行python

demo1:

func main() {
	cmd := exec.Command("ls", "-lah")
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("cmd.Run() failed with %s\n", err)
	}
	fmt.Printf("combined out:\n%s\n", string(out))

demo2:

func main() {
	cmd := exec.Command("ls", "-lah")
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		log.Fatalf("cmd.Run() failed with %s\n", err)
	}
	outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
	fmt.Printf("out:\n%s\nerr:\n%s\n", outStr, errStr)

上面是通过exec.Command的方式调用shell命令或者脚本,demo1通过cmd.CombineOutput的方式获取进程的输出以及错误信息,demo2通过重定向到标准输出,标准错误从而获取。这两种方法因为封装的比较好,操作比较简单。 下面讲一下通过开启一个新的进程来运行的方式

demo3: startProcess调用, 详见参考4

const (
	_LOG_FILE = "out.log"
)

func readLines(path string) ([]string, int, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil,0, err
	}
	defer file.Close()

	var lines []string
	linecount :=0
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
		linecount++
	}
	return lines,linecount,scanner.Err()
}

func StartProcessExecShell() {
	cmdToRun := "./test.sh"
	//cmdToRun := "/path/to/someCommand"
	args := []string{" ", " "}
	procAttr := new(os.ProcAttr)
	//打开一个 *File

	stdOut, _ := os.OpenFile(_LOG_FILE, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
	procAttr.Files = []*os.File{os.Stdin, stdOut, os.Stderr}
	process, err := os.StartProcess(cmdToRun, args, procAttr);
	//fmt.Printf("ERROR Unable to run %s: %s\n", cmdToRun, err.Error())
	//go os.StartProcess(cmdToRun, args, procAttr)
	if err != nil{
		fmt.Printf("ERROR Unable to run %s: %s\n", cmdToRun, err.Error())
		return
	}
	fmt.Printf("%s running as pid %d\n", cmdToRun, process.Pid)
	process.Wait()
	outputStr, _,  err := readLines("./out.log")
	if err != nil {
		//log.Fatalf("error: %v", err)
		fmt.Println("error = ", err)
	}
	fmt.Println("final result = ",outputStr)
}

简单讲解一下上面的代码, os.StartProcess开启一个进程去执行传入的命令, 它的输出可以指定输出到文件,也可以指定到标准输出(demo中所示的是指定输出到本地的文件out.log),最后在主进程里调用process.Wait()等待子进程处理完,然后打印输出。网上大部分博客都没有讲解如何获取os.StartProcess的输出,大部分只是打印一下进程id(Pid)。

执行shell遇到Exec format error

检查shell 脚本的正确格式是否如下:

#! /bin/bash

...

三、总结

1.跨进程,不同语言,最好还是通过rpc的方式去调用,go是静态语言,python是动态语言,可以通过go-python包来实现go直接调用python的方式,但是不优雅,也不好调试,不好拓展,同时也拖慢了go的性能;

2.go执行shell脚本一般有两种方式,exec.Command和os.StartProcess,其中cmd的方式比较方便获取子进程的结果

四、参考

https://studygolang.com/articles/11128

https://zhuanlan.zhihu.com/p/33445304

https://colobu.com/2017/06/19/advanced-command-execution-in-Go-with-os-exec/

http://lierhua.top/2019/02/03/golang%E5%88%9B%E5%BB%BA%E8%BF%9B%E7%A8%8BStartProcess/

进程原理

我们今天的关于从Shell脚本调用Python函数shell脚本调用python脚本的分享就到这里,谢谢您的阅读,如果想了解更多关于bash – 如何将stdin从shell脚本重定向到shell脚本中的命令?、bash – 无法从shell脚本调用Openscad -D命令行、bash – 通过sudo – 环境变量从另一个shell脚本调用shell脚本?、go执行python/shell脚本的相关信息,可以在本站进行搜索。

本文标签: