【问题标题】:Bash command works in terminal but not in scriptBash 命令在终端中有效,但在脚本中无效
【发布时间】:2018-01-03 22:44:47
【问题描述】:

我正在尝试运行带有一些参数的 C 可执行文件 (rtklib)。相同的命令在终端中似乎可以正常工作,但是当我在 sh 文件中运行它时,可执行文件会引发错误。

bash 脚本:

#!/bin/bash

# path to CUI executables
convbindir="/home/odroid/gitLibs/RTKLIB-master/app/convbin/gcc"
rnx2rtkpdir="/home/odroid/gitLibs/RTKLIB-master/app/rnx2rtkp/gcc"

datafiledir="/home/odroid/bashExample/datafiles"

basedir="$datafiledir/base*/"


cd $rnx2rtkpdir



# Do post process from each base to rover (should be 2)
for roverdir in $datafiledir/rover*/; do
    #echo "$roverdir" # absolute path to rover folder i.e. /home/odroid/bashExample/datafiles/rover2/ 
    #echo "basedir = $basedir" 

    rovernum="${roverdir: -2:-1}"
    #echo "$rovernum"   
    ls
    #echo "****************"
    echo "executing: $ ./rnx2rtkp -k optsEmlid.conf -o "$roverdir"rover"$rovernum".pos "$roverdir"*.obs "$basedir"*.obs "$basedir"*.nav"
    ./rnx2rtkp -k optsEmlid.conf -o "$roverdir"rover"$rovernum".pos "$roverdir"*.obs "$basedir"*.obs "$basedir"*.nav
    #echo "****************"
done

输出(无导航数据导航数据错误):

odroid@odroid:~/bashExample$ ./autopostprocess.sh 
ephemeris.o  makefile    opts4.conf  ppp_ar.o   rnx2rtkp    rtcm.o
geoid.o      options.o   optsEmlid.conf  ppp.o      rnx2rtkp.o  rtkcmn.o
gpsdata      opts1.conf  out.pos     preceph.o  rtcm2.o rtkpos.o
ionex.o      opts2.conf  pntpos.o    qzslex.o   rtcm3e.o    sbas.o
lambda.o     opts3.conf  postpos.o   rinex.o    rtcm3.o solution.o
executing: $ ./rnx2rtkp -k optsEmlid.conf -o /home/odroid/bashExample/datafiles/rover2/rover2.pos /home/odroid/bashExample/datafiles/rover2/*.obs /home/odroid/bashExample/datafiles/base*/*.obs /home/odroid/bashExample/datafiles/base*/*.nav
invalid option value pos1-snrmask (optsEmlid.conf:7)
no nav datanav data
ephemeris.o  makefile    opts4.conf      ppp_ar.o   rnx2rtkp    rtcm.o
geoid.o      options.o   optsEmlid.conf  ppp.o      rnx2rtkp.o  rtkcmn.o
gpsdata      opts1.conf  out.pos     preceph.o  rtcm2.o rtkpos.o
ionex.o      opts2.conf  pntpos.o    qzslex.o   rtcm3e.o    sbas.o
lambda.o     opts3.conf  postpos.o   rinex.o    rtcm3.o solution.o
executing: $ ./rnx2rtkp -k optsEmlid.conf -o /home/odroid/bashExample/datafiles/rover3/rover3.pos /home/odroid/bashExample/datafiles/rover3/*.obs /home/odroid/bashExample/datafiles/base*/*.obs /home/odroid/bashExample/datafiles/base*/*.nav
invalid option value pos1-snrmask (optsEmlid.conf:7)
no nav datanav data

手动在终端上执行(我 ctr+c 提前退出,注意我复制粘贴了我在脚本中打印的确切命令,即执行后的文本:$)):

odroid@odroid:~/gitLibs/RTKLIB-master/app/rnx2rtkp/gcc$ ./rnx2rtkp -k optsEmlid.conf -o /home/odroid/bashExample/datafiles/rover2/rover2.pos /home/odroid/bashExample/datafiles/rover2/*.obs /home/odroid/bashExample/datafiles/base*/*.obs /home/odroid/bashExample/datafiles/base*/*.nav
invalid option value pos1-snrmask (optsEmlid.conf:7)
^Cocessing : 2018/01/03 21:05:47 Q=0
odroid@odroid:~/gitLibs/RTKLIB-master/app/rnx2rtkp/gcc$ 

【问题讨论】:

  • 当您引用扩展时,会阻止 glob 被扩展。
  • @CharlesDuffy 你能在答案中澄清更多吗?我是 bash 的新手,谢谢。
  • 您希望"$datafiledir"/base*/ 匹配多少个不同的目录?如果只有一个,那就写basedir=( "$datafiledir"/base*/ )
  • 不要使用echo 来表示命令在运行时会做什么,而是使用bash -x your-script
  • 作为为什么使用echo这种方式是错误的简化示例,将printf '%s\n' "hello world"echo printf '%s\n' "hello world"的输出进行比较。

标签: linux bash ubuntu


【解决方案1】:

echo 的输出不代表内容是否被引用,尽管引号在解释命令的方式方面非常重要。

执行此操作的安全方法是将您的 glob 扩展为一个数组,然后验证数组的内容以检查 glob 是否扩展为恰好一个项目(如您所期望的那样)。这可能类似于以下内容:

shopt -s nullglob
base_inputs=( "$datafiledir"/base*/*.{obs,nav} )

for roverdir in "$datafiledir"/rover*/; do
  roverdir=${roverdir%/}; rovernum=${roverdir##*/rover}
  ./rnx2rtkp \
    -k optsEmlid.conf \
    -o "${roverdir}/rover${rovernum}.pos" \
    "$roverdir"/*.obs \
    "${base_inputs[@]}"
done

【讨论】:

  • 我假设他想处理所有目录中与$basedir匹配的所有匹配文件。
  • 可能是。如果我们有更好的规范会很有帮助。
  • 有 1 个基本目录,但我不知道它的名称,但名称中包含“base”一词
  • 啊——那么我的first revision 是合适的(因为它专注于安全地验证该假设)。
  • 您在哪里检查 glob 在您的答案中是否扩展为恰好一个?
【解决方案2】:

问题是您在执行命令时引用了$basedir,因此它没有扩展* 通配符,而是在寻找一个字面上名为base* 的目录。改为:

    ./rnx2rtkp -k optsEmlid.conf -o "$roverdir"rover"$rovernum".pos "$roverdir"*.obs $basedir*.obs $basedir*.nav

但是,这是有问题的,因为如果$basedir 中的任何目录在其名称中包含空格,它将不起作用,因为分词也已完成。

【讨论】:

  • 我同意这可以解决眼前的问题,但我不同意——强烈反对——这是一种合适的教学实践。遵循此处给出的建议的人将永远无法使用带空格的文件名。
  • 是的,我有点同意。如果您可以展示更好的方法,请发布答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-12
  • 1970-01-01
  • 2021-02-20
  • 2015-08-29
  • 1970-01-01
相关资源
最近更新 更多