【问题标题】:passing variables from bash to executable (which reads argument with stdin)将变量从 bash 传递到可执行文件(使用标准输入读取参数)
【发布时间】:2015-04-29 15:11:02
【问题描述】:

我有以下 test.cpp c++ 程序

#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

int main()
{
    float a,b,c;
    cout<<"Give 1st number";
    cin>>a;
    cout<<"Give 2nd number:";
    cin>>b;

    c=a+b;
    cout<<"\n"<<a<<"+"<<b<<"="<<c<<endl;

return 0;
}

我想创建一个 shell 脚本 来提供输入变量。 我知道如何传递一个变量,我想知道是否有办法传递 2 个变量... 像下面这个不起作用的 test.sh 文件

#!/bin/bash

g++ test.cpp -o testexe
chmod +x testexe

a=1
b=2

./testexe <<< $a $b

【问题讨论】:

  • 你的意思是像echo $a $b | ./testexe
  • ./testexe &lt;&lt;&lt;$'$a\n$b\n' 或类似的应该也可以工作 $'' 需要在那里获得一个文字换行符(用于单行演示),但可以在多行上完成。
  • 因为这是关于 shell 部分而不是 C++ 部分,您可能想要松开 c++ 标签。否则某些 C++ 人员可能会阅读该问题并对该代码发出冗长的哀号(重复包含、不必要的包含、C 头包含、有问题的 using 指令、奇怪的缩进、Missingwhitespacetomakeyourcodeunreadable,...)
  • @EtanReisner, $'$a\n$b\n' 不会扩展变量。
  • @CharlesDuffy 好点。我以为它会(我基本上从不使用它),因为它扩展了转义。所以&lt;&lt;"$a"$'\n'"$b"对于单行使用是必要的(假设输入需要换行)。

标签: bash variables executable stdin


【解决方案1】:

不仅要兼容 bash,还要兼容 /bin/sh——同时避免管道开销——使用 heredoc:

./testexe <<EOF
$a
$b
EOF

如果您不关心管道开销(并且仍然保持/bin/sh 兼容性,使用&lt;&lt;&lt; 的任何答案都缺乏):

printf '%s\n' "$a" "$b" |  ./testexe

如果您不关心/bin/sh 的兼容性:

./testexe <<<"$a"$'\n'"$b"

【讨论】:

    【解决方案2】:

    您应该如下更改您的 C++ 程序和脚本:

    int main(int argc, const char*argv[])
    {
        float a,b,c;
        a=std::stof(argv[1]);
        b=std::stof(argv[2]);
        c=a+b;
        cout<<"\n"<<a<<"+"<<b<<"="<<c<<endl;
        return 0;
    }
    
    
    #!/bin/bash
    
    g++ test.cpp -o testexe
    chmod +x testexe
    
    a=1
    b=2
    
    ./testexe  $a $b
    

    【讨论】:

    • 回避问题而不是回答问题,不是吗?
    • ` test.cpp: In function 'int main(int, char**)': test.cpp:12:6: error: cannot convert 'char*' to 'float' in assignment a =argv[1]; ^ test.cpp:13:6: error: cannot convert ‘char*’ to ‘float’ in assignment b=argv[2]; ^ 给出第一个数字:^C `
    • @OrestisKotsas,...顺便说一下——回避这个问题是正确的做法。您应该尽可能从命令行中取出参数,而不是标准输入。
    • @Charles Duffy 回避问题?你是什​​么意思?原谅我,但是我的英语水平不是很好……这是我正在处理的代码示例,要更改代码的结构并不容易。我只是想要基本的想法......
    • @OrestisKotsas,“回避问题”,意思是做一些避免你问的问题的事情,而不是实际解决所问的字面问题。在这种情况下,从命令行(从 argv 数组)读取参数比从标准输入读取参数更好,但是您专门询问了标准输入——因此直接回答将涉及标准输入;这个尝试向您展示一种更好的做法(尽管它有问题)。
    【解决方案3】:

    像这样:

    echo "$a $b" | ./testexe
    

    或者:

    arr=("$a" "$b")
    ./testexe <<< "${arr[*]}"
    

    或者:

    ./testexe <<< "$a $b"
    

    或者:

    ./testexe <<< "$a"$' '"$b"
    

    如果您希望它也适用于字符串变量(带有空格),请使用 新行 作为两个变量之间的分隔符,而不是单个空格。

    例如:

    echo "$a"$'\n'"$b" | ./testexe
    

    【讨论】:

    • echo $a $b 在这里工作,其中值保证为数字(除非 IFS 设置为包含这些数字中的数字的值,在这种情况下,这将在没有引号的情况下中断),但它是一般的不确定实践——参数得到字符串拆分和全局扩展。假设您传入的是文件名而不是数字;如果该名称类似于*** HELLO WORLD ***.txt,则第一组*s 将被全局扩展,并替换为当前目录中的文件名,而第二组将替换为文本文件名列表。
    • 因此,echo "$a $b" 是更安全的替代品;同样,printf '%s %s\n' "$a" "$b".
    • 当前给出的数组建议并不能解决通配问题,因为在将值放入数组时您仍在进行不带引号的赋值,并且由于${foo[@]} 的语义存在潜在的前向兼容性问题当被视为标量值时是未定义的(因此可以更改)(在这种情况下您应该使用"${foo[*]}")。
    • 所以:arr=( "$a" "$b" ); ./testexe &lt;&lt;&lt;"${arr[*]}" 会更正确。
    • @Jahid, ${foo[*]} 通过使用IFS 的第一个字符或默认情况下的空格分隔每个元素,将数组组合成一个字符串。相比之下,"${foo[@]}" 在引用时将数组作为单独的元素发出。当它没有被引用时,或者在只有一个字符串可用的情况下,它的行为更加模棱两可,这就是为什么"${foo[*]}" 在这些情况下更可取(但仅限于那些情况)。
    猜你喜欢
    • 1970-01-01
    • 2013-03-18
    • 1970-01-01
    • 2017-08-20
    • 2011-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多