如何将多行输入从标准输入读取到变量中以及如何在 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读入变量AA进行各种操作 管道 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)中打印出来?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Java 中的标准输入中读取整数值

如何将变量作为标准输入从 PHP 传递到命令行

go:读取标准输入

go:读取标准输入

请问ABAP中,如何从标准屏幕上获取到选择屏幕中一个字段的输入值。可以举个例子吗?这里感谢大家了。

从标准输入读取所有文本到字符串