了解 bash 命令行中的 read、echo 和 grep 命令

了解 bash 命令行中的 read、echo 和 grep 命令

谁能一步一步解释一下 bash 行中发生了什么?我是新来的,试图了解这段代码是如何工作的,特别是来自echo

read char; echo -e "YES\nNO\n" | grep -i $char

答案1

该行上的命令将字符串读入变量char,可能是以用户交互的方式。

echo+管道grep尝试确定输入的字符串是否为肯定字符串。它通过将单词YESNO与输入的字符串(以输入的字符串作为模式)进行匹配来实现此目的,不区分大小写。如果用户输入单词中存在的大写或小写字符或子字符串YES,结果将是YES;如果他们输入字符串中存在的大写或小写字符或子字符串NO,则结果将为NO。输入类似的内容maybe将导致空输出。

这种方法的缺点是,例如,如果用户输入 ,.YES都会NO匹配,因为grep会将点视为与任何字符匹配的正则表达式。由于$char的调用中未加引号grep,因此如果用户输入诸如/*/*/*/*/../../../../*/*/*/*input 之类的 shell 通配模式(示例取自忘记在 bash/POSIX shell 中引用变量的安全隐患)。您还可能通过输入eg -r -o -e . /(将每个非二进制文件的每个字符单独输出一行,前面加上该文件所属文件的路径名)来导致命令的输出混乱。

您显示的代码“奇怪且不寻常”,因为它使用用户输入本质上是代码,即它使用用户输入作为图案,并测试静态数据针对这种可变模式。这与通常所做的相反,通常的做法是获取用户的输入并根据静态模式测试此可变数据。

更常见的是使用类似于以下的代码:

read -p 'Yes/[N]o: ' yesno
if [[ $yesno == [Yy]* ]]; then
   # code for affirmative
else
   # code for non-affirmative
fi

上面的代码从用户处读取一个字符串并测试它是否以 ayY字符开头。如果是,则将采用该语句的第一个分支if,但否则将默认采用该else分支。

显然,您还可以测试整个单词YES,或者[Yy][Ee][Ss]不区分大小写的匹配,或者通过验证进行正确的输入循环:

while true; do
    read -p 'Yes/No: ' yesno

    if [ "$yesno" = Yes ] || [ "$yesno" = No ]; then
        break
    fi

    echo 'Please enter "Yes" or "No"' >&2
done

# $yesno is either Yes or No here

(或类似的东西)。

请注意上面的两个示例代码如何仅将用户的输入用作数据而不是模式。

将您的原始命令至少重写为一些惯用的命令(但功能不同,并且可能并非万无一失),会将其变成

read yesno; printf '%s\n' "${yesno^^}" | grep -i -w -E 'yes|no'

如果用户输入or ,这将返回大写字母YESor 。这在功能上是不同的,因为它要求用户输入的内容不仅仅是a等。NOyesnoeyes

答案2

好吧,让我们依次执行每个命令:

read char

这将从标准输入(通常是您的键盘,但可能是间接文件或管道流;见下文)读取,并将接收到的数据放入名为 的变量中char

echo -e "YES\nNO\n"

echo将向标准输出(通常是终端)显示提供的参数。该-e开关(通常但并非总是如此;echo在一致性实现方面存在一些问题)允许您e转义某些字符以进行一些基本的格式化。在本例中,它使用的是 using \n,它是转义的n,它是 ewline 的简写n

grep -i $char

grep是一个搜索提供的输入以查看是否有与提供的模式匹配的工具。该-i开关告诉它是i不区分大小写的搜索。

|命令之间是一个“管道”。这将第一个命令的输出连接到第二个命令的输入,这意味着将在该语料库中搜索变量内容中反映的模式:echogrepgrepchar

YES
NO

此命令序列的实际结果是查看提供的输入(根据变量名称假设为单个字符,但未检查这一点)。如果该字符是YESyes,则输出将为YES。如果该字符是NOn、 或o,则输出将为NO。但是,如果(例如)输入是yoor ne,则不会输出任何内容。

如前所述,不检查输入是一个字符的假设。这不是给定示例命令序列中唯一的反模式。例如,变量没有被引用;并且正在使用正则表达式工具 ( grep),而无需对输入进行正则表达式通配符筛选。

答案3

从 中读取“字符”(而不是:字符串)/dev/stdin。意思是:你输入它。

然后两行输出到/dev/stdout.意思是你的控制台。

然后通过管道(“|”)将其 grep 为不区分大小写的输入版本。

这意味着如果您输入“bar”,它将简单地完成,没有任何明显的输出,但如果您输入“y”,那么它会输出“YES”行,甚至很可能突出显示“Y”

相关内容