如何读取STDOUT到一系列变量

时间:2010-10-04 02:48:21

标签: bash

我有一个名为mythicalPythonBindings.py的python脚本。它输出类似

的内容
Establishing database connection
chanid = 1952
starttime = 2010-09-29 08:12:00
endtime = 2010-09-29 08:30:00
basename = 1952_20100929081200.mpg
stars = 0.0

我需要在bash脚本中将此信息读入同名变量中。我的bash脚本看起来像这样

#! /bin/bash

/usr/local/bin/mythicalPythonBindings.py --filename='1952_20100929081200.mpg' --DBHostName='192.168.1.110' --DBName='mythconverg' --DBUserName='mythtv' --DBPassword='mythtv' --output=./ReturnFile.txt --display|
   while read line
     do 
     case "$line" in
         "basename = "* ) 
              echo $line
              basename=`echo "$line" |sed s/'basename = '//g`
              echo $basename
         ;;
     esac
   done
echo $basename
#doing more stuff 

问题是当在mythicalPythonBindings.py的管道输出中设置变量时,它不会导出变量。语句“echo $ basename”(在管道输出中)有效,但是第二个“echo $ basename”(在管道输出之外)不起作用。

如何设置这些变量以用于脚本的其余部分?

编辑:我需要在其他命令中使用此变量,而不将数据保存到以后必须删除的文件中。

4 个答案:

答案 0 :(得分:3)

while循环在输入内容时创建子shell。为避免这种情况,您可以将流程替换重定向到done

pythonfunc () {
    /usr/local/bin/mythicalPythonBindings.py --filename='1952_20100929081200.mpg' --DBHostName='192.168.1.110' --DBName='mythconverg' --DBUserName='mythtv' --DBPassword='mythtv' --output=./ReturnFile.txt --display
}

while ...
do
    ...
done < <(pythonfunc)
echo $basename

我会用

read var equals value
# do some validation
declare $var=$value

以这种方式使用declare可以避免使用eval

答案 1 :(得分:0)

#!/bin/sh
./testpyscri.sh | (
   while read line
     do 
     case "$line" in
         "basename = "* ) 
    echo $line
              basename=`echo "$line" |sed s/'basename = '//g`
                echo $basename
         ;;
     esac
   done
   echo and also $basename
)

我进行了一些更改以轻松复制和演示结果,但唯一重要的变化是添加了单组parens。

so ross$ ./testpyscri.sh  | ./pyscri.sh 
basename = 1952_20100929081200.mpg
1952_20100929081200.mpg
and also 1952_20100929081200.mpg

更新

应该易于理解上述设计模式,实际上可以在管道的任何一端执行任意复杂的脚本。但也许你想要一种不同的设计。尝试这样的事情:

so ross$ expand < test.sh
#!/bin/sh
# here is an alternate design pattern
if [ x$1 != x-a ]; then
  echo abc | ./$0 -a
  exit 0
fi
read x
echo $x
so ross$ ./test.sh
abc
so ross$ 

答案 2 :(得分:0)

两个关键变化:

#! /bin/bash
/usr/local/bin/mythicalPythonBindings.py --filename='1952_20100929081200.mpg' \
    --DBHostName='192.168.1.110' --DBName='mythconverg' --DBUserName='mythtv' \
    --DBPassword='mythtv' --output=./ReturnFile.txt --display |
{
while read var equals value
do
    if [ $equals = "=" ]
    then
        eval $var=\"$value\"
    fi
done

echo basename=$basename
echo starttime=$starttime
echo endtime=$endtime
echo stars=$stars
echo chanid=$chanid
# ...rest of script...
}
  1. 使用shell的内置拆分工具,加上eval来设置变量,而无需知道变量是什么(并且没有为每个不同的变量分别进行分配)。测试忽略输出的第一行。
  2. 使用{...}的I / O分组工具捕获脚本的其余部分,以便循环后在循环中设置的变量可用。
  3. 您可以使用括号代替大括号;在这种情况下,它相同的事情。通常,I / O分组不会启动子shell,这对于在执行代码块时避免重复重定向很有用,同时仍允许在块外部看到设置在代码块中的变量。

答案 3 :(得分:0)

这是使用eval的另一个版本 它假定:

  1. Python输出由=分隔的变量和值。
  2. 使用与-F '='的Awk将输入分解为variablevalue
  3. 使用Sed。
  4. 删除变量和值的前导和尾随空格字符

    Bash代码:

    #!/bin/bash
    
    while read line
    do
        var=$(echo $line | awk -F '=' '{print $1}' | sed 's/^[ \t]*//;s/[ \t]*$//')
        val=$(echo $line | awk -F '=' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')
    
        eval $var="$val"
        echo $python_var
    done
    

    示例用法:

    >> echo "python_var = 1234" | ./script.sh 
    >> 1234