如何从stdin读取mutliline输入到变量以及如何在shell中打印出一个(sh,bash)?

56 bash shell stdin multiline

我想做的是以下内容:

  1. 从多行输入读stdin入变量A
  2. 进行各种操作 A
  3. A,而不会失去定界符符号(\n,\r,\t等)到另一个命令

目前的问题是,我无法用read命令读取它,因为它停止在换行时读取.

我可以读取stdin cat,像这样:

my_var=`cat /dev/stdin`
Run Code Online (Sandbox Code Playgroud)

,但后来我不知道如何打印它.因此换行符,制表符和其他分隔符仍然存在.

我的示例脚本如下所示:

#!/usr/local/bin/bash

A=`cat /dev/stdin`

if [ ${#A} -eq 0 ]; then
        exit 0
else
        cat ${A} | /usr/local/sbin/nextcommand
fi
Run Code Online (Sandbox Code Playgroud)

Tan*_*lus 64

这对我有用:

myvar=`cat`

echo "$myvar"
Run Code Online (Sandbox Code Playgroud)

引号$myvar很重要.

  • 应该读myvar = $(cat); echo"$ {myvar}" - 但我的解决方案完全正确. (4认同)
  • @appenwarr:引用是至关​​重要的,否则你依赖于IFS是默认值,这是一个非常糟糕的做法. (4认同)
  • gnud,你建议的那些额外引号字符实际上并没有改变功能. (2认同)
  • @CommaToast,这是回声的函数,而不是引号。使用-n标志(或您平台上的等效标志)。回声只是用法的一个例子。 (2认同)

Ing*_*kat 25

在Bash中,还有另一种方式; man bash提到:

命令替换$(cat file)可以替换为等效但更快$(< file).

$ myVar=$(</dev/stdin)
hello
this is test
$ echo "$myVar"
hello
this is test
Run Code Online (Sandbox Code Playgroud)

  • 公平地说,unix是在1946年设计的并不是你的错,而且基本上它是一个美化的打字机,就其而言.我可以看到回车在unix的大脑里来回走动.它不能被要求像其他角色一样对待新行.不,它只是*有*恢复其打字机爬行动物的大脑.但无论如何,我能找到的唯一解决方法是`var = \`cat; echo x \``然后在准备输出它时,输出`$ {var%x}`以保留换行符(或缺少换行符).丑陋但是,它有效...... (5认同)
  • @CommaToast:并且`$(...)` 将删除任何尾随换行符,因此它们完美地结合在一起,不是吗?您可以轻松切换到 `printf` 来避免这种情况。 (2认同)

Ser*_*iev 12

tee完成这项工作

#!/bin/bash
myVar=$(tee)
Run Code Online (Sandbox Code Playgroud)


小智 7

是的它也适合我.谢谢.

myvar=`cat`
Run Code Online (Sandbox Code Playgroud)

是相同的

myvar=`cat /dev/stdin`
Run Code Online (Sandbox Code Playgroud)

嗯,是.从bash手册页:

用双引号括起字符会保留引号内所有字符的字面值,但$,`,\除外,并且,当启用历史记录扩展时,!字符$和`在双引号中保留其特殊含义.


Ing*_*kat 7

如果您确实关心在输出末尾保留尾随换行符,请使用以下命令:

myVar=$(cat; echo x)
myVar=${myVar%x}
printf %s "$myVar"
Run Code Online (Sandbox Code Playgroud)

这使用了这里的技巧。

  • 好的。最后两行可以用 `echo -n "${myVar%x}"` 替换,但我想首先修复变量更*模块化*。 (2认同)

Doc*_*ger 5

[更新]

如果管道中没有任何东西,此作业将无限期挂起。

var="$(< /dev/stdin)"
Run Code Online (Sandbox Code Playgroud)

我们可以通过read对第一个字符设置超时来防止这种情况。如果超时,返回码将大于128,我们将知道STDIN管道(aka /dev/stdin)为空。

否则,我们将通过以下方式获得STDIN的其余部分:

  • IFS仅将read命令设置为NULL
  • -r
  • 用消除read的分隔符-d ''
  • 最后,将其附加到我们最初获得的角色

从而...

__=""
_stdin=""

read -N1 -t1 __  && {
  (( $? <= 128 ))  && {
    IFS= read -rd '' _stdin
    _stdin="$__$_stdin"
  }
}
Run Code Online (Sandbox Code Playgroud)

这种技术避免了使用var="$(command ...)"Command Substitution,而Command Substitution在设计上总是会剥离任何尾随的换行符。

如果首选Command Substitution,则为了保留尾随换行符,我们可以在的内部输出中附加一个或多个定界符$(),然后在外部将其删除。

例如(注意$(parens)第一个命令和${braces}第二个命令) ...

_stdin="$(awk '{print}; END {print "|||"}' /dev/stdin)"
_stdin="${_stdin%|||}"
Run Code Online (Sandbox Code Playgroud)