如何将多行输入从标准输入读取到变量中以及如何在 shell(sh,bash)中打印出来?
Posted
技术标签:
【中文标题】如何将多行输入从标准输入读取到变量中以及如何在 shell(sh,bash)中打印出来?【英文标题】:How to read mutliline input from stdin into variable and how to print one out in shell(sh,bash)? 【发布时间】:2010-09-17 19:08:49 【问题描述】:我想做的是:
-
将多行输入从
stdin
读入变量A
对A
进行各种操作
管道 A
不丢失分隔符(\n
、\r
、\t
等)到另一个命令
目前的问题是,我无法用read
命令读入它,因为它在换行处停止读取。
我可以使用cat
读取标准输入,如下所示:
my_var=`cat /dev/stdin`
,但是我不知道如何打印它。这样换行符、制表符和其他分隔符仍然存在。
我的示例脚本如下所示:
#!/usr/local/bin/bash
A=`cat /dev/stdin`
if [ $#A -eq 0 ]; then
exit 0
else
cat $A | /usr/local/sbin/nextcommand
fi
【问题讨论】:
【参考方案1】:这对我有用:
myvar=`cat`
echo "$myvar"
$myvar
周围的引号很重要。
【讨论】:
应该读 myvar=$(cat); echo "$myvar" - 否则我的解决方案完全正确。 gnud,你建议的那些额外的引号字符实际上并没有改变功能。 @appenwarr:引号很重要,否则您依赖 IFS 为默认值,这是一个非常糟糕的做法。 失败。echo "$myvar"
向文件添加一个换行符(如果之前没有的话)。
@CommaToast,这是回声的功能,而不是引号。使用-n
标志(或您平台上的等效标志)。 echo 只是一个使用示例。【参考方案2】:
在 Bash 中,有另一种方法; man bash
提及:
命令替换
$(cat file)
可以替换为等效但更快的$(< file)
。
$ myVar=$(</dev/stdin)
hello
this is test
$ echo "$myVar"
hello
this is test
【讨论】:
@CommaToast:$(...)
将删除任何尾随的换行符,因此它们完美地结合在一起,不是吗?您可以轻松切换到printf
来避免这种情况。
不,它们不能完美地结合在一起。无论在这个解决方案中是什么,无论是否有一个开始,你最终都会得到一个尾随换行符。如果你随意切换到 printf,现在你将永远不会有一个尾随换行符,即使有一个。
好吧,公平地说,unix 是在 1946 年设计的,就它而言,基本上是一台美化的打字机,这不是你的错。我只能看到在 unix 的大脑中来回回车。只是不能要求将换行符像其他所有字符一样对待。不,它只是必须恢复到打字机爬行动物的大脑。但无论如何,我能找到的唯一解决方法是var=`cat; echo x`
,然后在准备输出它时,输出$var%x
,以便保留换行符(或缺少换行符)。丑到不行,但是,它的工作原理......
@Nikhil Ctrl-C 中止你的整个脚本;很难将其转发给子命令。要在 N 行之后跳过读取输入,我会使用 head
: myVar=$(head -n 10 /dev/stdin)
如果这不适合您,您可能需要自己实现 read
-loop。
@Nikhil - 使用 Ctrl-D 而不是 Ctrl-C 在此处终止多行字符串的输入。【参考方案3】:
三通完成这项工作
#!/bin/bash
myVar=$(tee)
【讨论】:
+1 因为 tee 很优雅,而且可以读进去。哇,谢谢!但是您没有回答问题,即如何通过更改换行符来打印它。【参考方案4】:[更新]
如果管道中没有任何内容,此分配将无限期挂起...
var="$(< /dev/stdin)"
我们可以通过为第一个字符设置超时read
来防止这种情况。如果超时,返回码将大于 128,我们会知道 STDIN 管道(又名 /dev/stdin
)是空的。
否则,我们通过...获得 STDIN 的其余部分
将IFS
设置为 NULL,仅用于 read
命令
使用-r
关闭转义
用-d ''
消除读取的分隔符。
最后,将它附加到我们最初得到的字符上
这样……
__=""
_stdin=""
read -N1 -t1 __ &&
(( $? <= 128 )) &&
IFS= read -rd '' _stdin
_stdin="$__$_stdin"
这种技术避免使用var="$(command ...)"
命令替换,按照设计,它总是会删除任何尾随的换行符。
如果首选命令替换,为了保留尾随换行符,我们可以在 $()
内的输出中附加一个或多个分隔符,然后将它们剥离到外面。
例如(注意第一个命令中的$(parens)
和第二个命令中的$braces
)...
_stdin="$(awk 'print; END print "|||"' /dev/stdin)"
_stdin="$_stdin%|||"
【讨论】:
【参考方案5】:是的,它也适用于我。谢谢。
myvar=`cat`
与
相同myvar=`cat /dev/stdin`
嗯,是的。来自bash
手册页:
用双引号括起来的字符 保留所有的字面值 引号内的字符, 除了 $、`、\ 和,当历史扩展是 启用,!字符 $ 和 ` 在双引号内保留它们的特殊含义。
【讨论】:
【参考方案6】:如果您确实关心在输出末尾保留尾随换行符,请使用:
myVar=$(cat; echo x)
myVar=$myVar%x
printf %s "$myVar"
这使用了here的技巧。
【讨论】:
不错。最后两行可以只替换为echo -n "$myVar%x"
但我想先修复变量更模块化。【参考方案7】:
Read 也可以用于设置选项 -d [DELIMITER],其中 `input' DELIMITER 是一个字符长。如果您设置-read d ''
,那么它会一直读取到 null 或所有输入。
请记住,无论如何,Bash 不能在变量中保存空字节。
read -d'' myvar
echo "$myvar"
Obs:虽然不保留尾随换行字节..
【讨论】:
以上是关于如何将多行输入从标准输入读取到变量中以及如何在 shell(sh,bash)中打印出来?的主要内容,如果未能解决你的问题,请参考以下文章