我有这样的剧本
1
| genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5 |
我想得到一个变量中由genhash生成的流。如何将其重定向到一个变量$hash,以便在条件内部进行比较?
1 2 3 4 5 6
| if [ $hash -ne 0 ]
then echo KO
exit 0
else echo -n OK
exit 0
fi |
使用$( ... )构造:
1
| hash=$(genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5) |
- 这将捕获命令的输出,但不使用重定向。如果因为更复杂的需求而实际需要使用重定向,请参阅我的答案。谷歌把你带到这里,对吧?为什么要去别的地方找你要找的答案?
- 实际上不是关于操作问题的答案
- @布鲁诺布隆诺斯基这对我很有用:result=$(( $your_command ) 2>&1)。
- @kayvar在使用$( ... )时使用了新的子shell,因此命令的结果不能与主shell中的结果相同。
DR
将"abc"存储到$foo中:
但是,因为管道会产生分叉,所以在管道末端之前必须使用$foo,所以…
1
| echo"abc" | ( read foo; date +"I received $foo on %D"; ) |
当然,所有这些其他的答案都显示出了不去做OP要求的事情的方法,但这真的让我们这些寻找OP问题的人搞砸了。
问题的答案是使用
read命令。这是你的做法
1 2 3 4 5 6 7 8 9
| # I would usually do this on one line, but for readability...
series | of | commands \
| \
(
read string;
mystic_command --opt"$string" /path/to/file
) \
| \
handle_mystified_file |
以下是它所做的以及为什么它很重要:
假设series | of | commands是一系列非常复杂的管道命令。
mystic_command可以接受文件的内容作为stdin而不是文件路径,但不能接受--opt参数,因此它必须作为变量输入。该命令输出修改后的内容,通常会被重定向到一个文件或通过管道传输到另一个命令。(如sed、awk、perl等)
read接受stdin并将其放入变量$string中。
不需要通过括号将read和mystic_command放入"子shell"中,但会使其像连续管道一样流动,就像两个命令在单独的脚本文件中的位置一样。
总有一个选择,在这种情况下,与我上面的例子相比,这个选择是丑陋的和不可读的。
1 2 3 4 5
| # my example above as a oneliner
series | of | commands | (read string; mystic_command --opt"$string" /path/to/file) | handle_mystified_file
# ugly and unreadable alternative
mystic_command --opt"$(series | of | commands)" /path/to/file | handle_mystified_file |
我的方法完全按时间顺序和逻辑。备选方案从第4个命令开始,将命令1、2和3推送到命令替换中。
我在这个脚本中有一个真实的例子,但是我没有把它作为上面的例子,因为它还有其他一些疯狂/混乱/分散注意力的bash魔法。
- 我也相信这是正确的答案。有些情况下,当到处都可以接受管道时,美元(…)不起作用。
- 别忘了结尾的分号!:)
- @帕特,分号去哪儿?我没有一个方便的神秘命令,但它看起来是对的?
- 起初,我以为@pat是建议我在神秘的"命令"之后加上一个;,或者我在read之后去掉一个。因为微笑,我觉得@pat只是在取笑我不一致。它不一致的原因是,如果将其压缩为一个内衬,那么它是所需的最小值。我用一个我称之为arg_barf的实用程序测试了这个。它基本上是我在构建bash脚本原型时使用的任何命令的代理。它将接受stdin和任何参数,将它们写入一个临时文件,并选择将一个文件cat到stdout/stderr,并返回一个非零状态。
- 对不起,我指的是read string;末尾的分号
- @Richardbronosky感谢您发布此答案。是否可以访问父进程中的变量(例如,在管道中更远处,例如在handle_mystified_file部分)?这似乎是不可能的,因为read在子进程中运行,而子进程不能影响父进程中的变量。我试图通过读取一个进程的输出作为另一个进程的参数,从使用tee的进程中分离输出,然后"重新连接"由tee划分的进程。
- 与上述问题相同,即访问父进程中的变量。另外,变量是否有存储多行字符串的方法?
- 不适合我:echo"test" | read ROLE_X; echo $ROLE_X不打印任何东西。
- @ PH?那个家伙?N,这不起作用,因为管道会创建流程分叉。我不得不加括号的另一个原因。echo"test" | (read ROLE_X; echo $ROLE_X )在stackoverflow.com/a/13764018/117471上了解更多关于这种分叉的信息。
- 仍然不适用于括号。ls | (read $x; echo $x)只打印ls输出的第一行。read'不能读取多行输出。
- @菲尔戈茨,那是因为你有埃多克斯。$使其成为一个变量访问(所以您说"读入这个变量访问")。应该是ls | (read x; echo $x)。
- 如果您的stdin要有多行,您可以使用read -d '' string。
- @布鲁诺布隆诺斯基,我不知道为什么你可以说"所有这些其他的答案都显示了不做那些行动要求的方式"。据我所知,接受的人是埃多克斯(14)。请考虑描述您的情况,以便在哪种情况下,read是唯一可行的选择。请注意,您仍然可以在echo $(cat <<<"works")内部进行重定向,并且可以使用echo"$(pstree)"获取多行字符串。
- @brunobronosky"如果你的stdin有多行,你可以使用read-d""字符串。"请考虑将其放入你的答案中,首先我发现你的解决方案在我的情况下完全不可用。关于所需括号的内容也很重要(read赋值给的变量在后面的命令中是空的,没有括号)。
- 我为不耐烦的谷歌用户添加了一个快速的tl;dr。希望你不介意。
- @我这么说是因为问题的标题是"如何将输出重定向到shell中的变量?"我的答案是第一个实际"将输出重定向到变量"。我喜欢"命令替换",并且一直使用它(就像任何半正派的黑客一样)。但是,当我需要重新定向输出时,我通常需要谷歌来实现,即使我写了这个答案,因为我不经常这样做。这是谷歌的热门话题,所以我希望它能回答我的问题。
- @布鲁诺布隆斯基,有其他选择是好的。我只是想说,如果你描述一下为什么你必须使用这种方法而不是被接受的方法,它会更有用。我承认你的话在我看来有点大胆。人们经常说一件事,但最终他们可能想说一些其他的事情,这是通过语言交流的一部分。尤其是当人们谈论一些他们还不知道的事情时。显然,替代品是可以接受的。很高兴知道你的情况,如果这个答案更合适的话。
- echo"abc" | (read foo; echo $foo)在终端中工作正常,但在bash脚本中使用时由于某些原因失败。
- @比比,我不知道你为什么有这个问题。我试着把你的行粘贴到一个文件中,从很多方面测试了它。gist.github.com/richardbronosky/&hellip;
- 但是,如何附加到EDOCX1[1]中?
- @马蒂纳斯朱塞维?这将是非常棘手的,因为管道制造叉子的方式。您可以在stackoverflow.com/a/13764018/117471中了解更多关于这个的信息,我可以以多种方式附加,但不知道您的具体情况,它肯定是次优的。我相当肯定,在尝试附加时,没有办法实现我的"时间和逻辑"目标。例如,多次这样称呼:read foo < <( echo -n $foo; date +%s, ); echo"value of foo: '$foo'"。
- 我使用它创建了一个bash函数,可以更简单地重用它。tovar(){read $1; echo $"$1";}、echo 'content' > file.txt; cat file.txt | tovar somevariable、echo $somevariable => content。
- @马里奥莉维奥弗洛雷斯,那不管用。我甚至都不知道该怎么做。
- 间距使阅读变得非常困难。基本上,我只是创建了一个函数,这样我可以通过管道连接到一个变量。如果我想要的变量名是myvar,我可以为我的用例做echo 'value' | tovar myvar。
1
| read hash < <(genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5) |
这种技术使用bash的"进程替换",不要与"命令替换"混淆。
以下是一些很好的参考资料:
- http://www.linuxjournal.com/content/shell-process-redirection
- http://tldp.org/ldp/abs/html/process-sub.html
- http://tldp.org/ldp/abs/html/commandsub.html?为了比较
- 这需要更多的赞成票。这几天唯一对我有效的解决方案。
- 当子命令不能在子shell中运行时,这很有用。谢谢!
- 我希望更多的人理解<(…)的用法,这是纯粹的敬畏。OP应该给出解释。基本上,它运行一个子进程,但不是通过管道传输,而是返回一个文件描述符。这允许您在需要文件的地方使用命令。例如(作为根)vimdiff /etc/sysconfig/iptables <(iptables-save),它最终打开了一个类似于/proc/23565/fd/63的文件名。是的,vim可以接受-作为文件名并从stdin中读取,但这只是一个例子。可能事情不使用-,或者使用<()允许的命令命令更清晰。
- @ PH?那个家伙?N,你能分享你的案子吗?这真的很有趣,因为我不希望支持<(...)功能,而back ticks ar不支持。<(...)是不错的,但大多数时候我用它和diff比较输出。
- @Ensonic,我不知道为什么在创建一个额外的子shell方面,<(...)应该比$(...)更好。有了GNU bash 4.4.12,当我做cat <(pstree -sH $$)的时候,我可以看到额外的bash在pstree之前与cat并行产生,而echo"$(pstree -sH $$)"则没有。这可能是因为为了解释$(...)shell可以简单地停止并运行其中的管道,并收集所有输出。对于<(...)shell,需要使用指向fd的参数生成命令,fd必须与正常的执行流一起在后台维护。
- @brunobronosky调用的<(...)语法是什么?我想找个别的地方了解一下。我知道$(...)被称为命令替换,但不知道该怎么称呼<(...)。
- @我编辑了答案,把你(和其他人)需要知道的包括在内。谢谢你的邀请。这对每个人都有好处。
- 这适用于多行输出。竖起大拇指寻求答案!
- 我希望我能多次投反对票
我想兼容的方式是:
1
| hash=`genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5` |
但我更喜欢
1
| hash="$(genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5)" |
- 感谢您提到兼容性。这就是我的环境所采用的方法,而其他人却没有。
- 没有必要对$(...)进行报价。
- 是的,有必要。如果输出中有一个*,取决于您以后如何处理它,它将尝试将其扩展为一个全局。
- @Koshinae,它将尝试扩展到echo $hash。但它会使*保持原样,就像你要做hash=$(echo '*'0); echo"$hash"一样。
- 如果结果是多个单词,它将创建一个数组否?因此,通过用引号包围它,它创建了一个字符串而不是字符串数组。不太确定,对bash来说是比较新的
- @Mathieudumulin,当我需要在数组中存储单词时,我使用ab=($(echo a b))。否则它将作为字符串分配。
如果管道太复杂,无法在$(...)中包装,请考虑编写函数。定义时可用的任何局部变量都将是可访问的。
1 2 3 4
| function getHash {
genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5
}
hash=$(getHash) |
http://www.gnu.org/software/bash/manual/bashref.html shell函数
你可以做到:
1
| hash=$(genhash --use-ssl -s $IP -p 443 --url $URL) |
或
1
| hash=`genhash --use-ssl -s $IP -p 443 --url $URL` |
如果要将整个管道的结果分配给变量,可以在上面的分配中使用整个管道。
- 我喜欢写反问词的人读当前发布的文章。-因为我一直都在读它们。
创建一个函数,将其作为要调用的命令来调用。在这种情况下,我需要使用ruok命令。
然后,调用函数并将其结果赋给变量。在本例中,我将结果分配给变量health。
1 2 3 4 5
| function ruok {
echo ruok | nc *ip* 2181
}
health=echo ruok *ip* |
使用$(`code`)构造函数时,有时会出错。
最后,我在这里找到了一些方法:https://stackoverflow.com/a/7902174/2480481
基本上,使用tee再次读取输出并将其放入变量中。这是您如何看到正常输出,然后从输出读取它。
不是吗?我想您当前的任务genhash将只输出一个字符串hash,因此可能对您有用。
我是如此的neewbie,仍然在寻找完整的输出&save into 1命令。当做。