bash 不传递参数时如何读取标准输入?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19619490/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 08:25:27  来源:igfitidea点击:

How to read stdin when no arguments are passed?

bashstdin

提问by aron23

Script doesn't work when I want to use standard input when there are no arguments (files) passed. Is there any way how to use stdin instead of a file in this code?

当我想在没有传递参数(文件)的情况下使用标准输入时,脚本不起作用。有什么办法可以在这段代码中使用stdin而不是文件吗?

I tried this:

我试过这个:

if [ ! -n  ] # check if argument exists
   then
   =$(</dev/stdin)  # if not use stdin as an argument
   fi

var=""
while read line
   do
   ...                # find the longest line
   done <"$var"

采纳答案by pilcrow

Just substitute bash's specially interpreted /dev/stdinas the filename:

只需替换特别解释/dev/stdin为文件名的bash :

VAR=
while read blah; do
  ...
done < "${VAR:-/dev/stdin}"

(Note that bash will actually use that special file/dev/stdinif built for an OS that offers it, but since bash 2.04 will work around that file's absence on systems that do not support it.)

(请注意,如果为提供它的操作系统构建,bash 实际上将使用该特殊文件,但由于 bash 2.04 将在不支持它的系统上解决该文件缺失的问题。)/dev/stdin

回答by Ryan

For a general case of wanting to read a value from stdin when a parameter is missing, this will work.

对于在缺少参数时想要从 stdin 读取值的一般情况,这将起作用。

$ echo param | script.sh
$ script.sh param

script.sh

脚本文件

#!/bin/bash

set -- "${1:-$(</dev/stdin)}" "${@:2}"

echo 

回答by mklement0

pilcrow's answerprovides an elegant solution; this is an explanation of why the OP's approach didn't work.

pilcrow 的回答提供了一个优雅的解决方案;这是对为什么 OP 的方法不起作用的解释

The main problem with the OP's approachwas the attempt to assign topositional parameter $1with $1=..., which won't work.

主要与OP的做法的问题要尝试分配给位置参数$1$1=...,这是行不通的。

The LHS is expanded by the shell to the valueof $1, and the resultis interpreted as the name of the variable to assign to - clearly, not the intent.

LHS由shell来扩展价值$1,并且结果被解释为变量的名称,分配到-显然,并不是意图。

The only way to assign to $1in bash is via the setbuiltin. The caveat is that setinvariably sets allpositional parameters, so you have to include the other ones as well, if any.

在 bash 中分配给$1set唯一方法是通过内置的. 需要注意的是,set总是设置所有位置参数,因此您必须包括其他参数(如果有)。

set -- "${1:-/dev/stdin}" "${@:2}"     # "${@:2}" expands to all remaining parameters

(If you expect only at most 1argument, set -- "${1:-/dev/stdin}"will do.)

(如果您期望最多只有1 个参数,set -- "${1:-/dev/stdin}"则可以。)

The above also corrects a secondary problem with the OP's approach: the attempt to store the contentsrather than the filenameof stdin in $1, since <is used.

以上还纠正了 OP 方法的一个次要问题:尝试在 中存储内容而不是stdin的文件名$1,因为<使用了。

${1:-/dev/stdin}is an application of bash parameter expansionthat says: return the value of $1, unless $1is undefined (no argument was passed) or its value is the empty string (""or ''was passed). The variation ${1-/dev/stdin}(no :) would only return /dev/stdinif $1is undefined(if it contains anyvalue, even the empty string, it would be returned).

${1:-/dev/stdin}是 bash参数扩展的应用程序,它说:返回 , 的值$1,除非$1未定义(未传递参数)或其值为空字符串(""''已传递)。变化${1-/dev/stdin}(无:)将只返回/dev/stdin如果$1不确定的(如果它包含任何值,甚至空字符串,它会被退回)。

If we put it all together:

如果我们把它们放在一起:

# Default to filename '/dev/stdin' (stdin), if none was specified.
set -- "${1:-/dev/stdin}" "${@:2}"

while read -r line; do
   ...                # find the longest line
done < ""


But, of course, the much simpler approach would be to use ${1:-/dev/stdin}as the filename directly:

但是,当然,更简单的方法是${1:-/dev/stdin}直接用作文件名:

while read -r line; do
   ...                # find the longest line
done < "${1:-/dev/stdin}"

or, via an intermediate variable:

或者,通过中间变量:

filename=${1:-/dev/stdin}
while read -r line; do
   ...                # find the longest line
done < "$filename"

回答by kenorb

Here is my version of script:

这是我的脚本版本:

#!/bin/bash
file=${1--} # POSIX-compliant; ${1:--} can be used either.
while IFS= read -r line; do
  printf '%s\n' "$line"
done < <(cat -- "$file")

If file is not present in the argument, read the from standard input.

如果参数中不存在文件,则从标准输入中读取。

See more examples: How to read from file or stdin in bash?at stackoverflow SE

查看更多示例:如何在 bash 中读取文件或标准输入?在 stackoverflow SE

回答by Oswald

Variables are assigned a value by Var=Valueand that variable is used by e.g. echo $Var. In your case, that would amount to

变量被赋值,Var=Value并且该变量被例如使用echo $Var。在你的情况下,这相当于

1=$(</dev/stdin)

when assigning the standard input. However, I do not think that variable names are allowed to start with a digit character. See the question bash read from file or stdinfor ways to solve this.

分配标准输入时。但是,我认为不允许变量名以数字字符开头。有关解决此问题的方法,请参阅问题bash 从文件或标准输入读取