乐趣区

关于后端:Shell-标准输入和输出

无论是要交给程序处理的数据,还是管制脚本的简略命令,都少不了输出和输入。程序要做的第一件事就是解决如同一阴一阳的“输出与输入”。

1、从文件获取输出

当咱们心愿向文件输入内容时,咱们能够通过符号 > 或 >> 实现。而用代表输出重定向的符号 < 能够从文件中读取数据,如下:

$ wc < my.file

之所以抉择这种形态的操作符号,起因在于它们能够从视觉上提醒重定向的方向。

很多 shell 命令能够承受一个或多个文件名作为参数,但如果没有给出文件名,命令就会从规范输出读取。应用这种命令时,能够采纳command filename 或者 command < filename,这两种模式的后果没什么区别。在这个例子中,wc 是这样,换作 cat 或其余命令,也是如此。

2、将数据与脚本寄存在一起

< 能够从文件读取数据,当你须要取得脚本输出,但又不想用独自的文件时,应用 <<(here-document)从命令行而非文件重定向输出文本。如果放在 shell 脚本中,则脚本文件能够同时蕴含数据与代码。

以下是名为 ext.sh 的 shell 脚本示例:

# 上面是 here-document
grep $1 <<EOF

mike x.123

joe x.234

sue x.555

pete x.818

sara x.822

bill x.919

EOF

当咱们运行此脚本,能够传入一个参数,如下调用:

$ ./ext.sh bill
# 输入以下内容
bill x.919

grep 命令查找第一个参数是否在指定文件中呈现,如果没有指定文件,那么它会在规范输出中查找。通过设置 here document,通知 shell 将规范输出重定向(长期)到此处。<< 语法示意咱们想创立一个长期输出源,EOF 是一个任意的字符串(你想用什么都行),用作长期输出的终止符。它并不属于输出的一部分,只是作为标记通知输出在哪里完结。

3、防止 here-document 中的怪异行为

here-document 在应用时可能会呈现一些怪异的行为。你想用上一节介绍的办法来保留一份简略的捐赠人列表,因而创立了一个名为 donors.sh 的文件,如下所示:

# 简略地查找慷慨的捐赠人

grep $1 <<EOF

pete $100

joe $200

sam $ 25

bill $ 9

EOF

然而运行时呈现了奇怪的输入:

$ ./donors.sh bill

pete bill00

bill $ 9

$ ./donors.sh pete

pete pete00

失常状况下(除非应用了本义语法),bash 手册页中是这样说的:“……here-document 的每一行都要执行参数扩大、命令替换以及算术扩大”。因而,最后的 donors 脚本中所产生的事件是捐献额被当作 shell 变量了。例如,$100 被视为 shell 变量 $1,随后跟着两个 0。这就是为什么咱们在搜寻“pete”时,失去的是 pete00;搜寻“bill”时,失去的是 bill00。

解决办法:

通过本义结尾标记中的任意或所有字符,批改脚本内容,敞开 here-document 外部的 shell 个性(留神察看 EOF 地位的变动):

# 简略地查找慷慨的捐赠人
grep $1 <<'EOF'

pete $100

joe $200

sam $ 25

bill $ 9

EOF

只管其中存在十分奥妙的区别,但也能够将 <<EOF 替换成 <<\EOF 或 <<‘EOF’,甚至是 <<E\OF,都没问题。只管这并不是最优雅的语法,但足以通知 bash 你心愿区别解决 here-document 中的内容。如果咱们本义了 EOF 的局部或全副字符,那么 bash 就晓得不必执行扩大,这样就合乎咱们的预期行为了。

$ ./donors.sh pete

pete $100

4、获取用户输出

输出不止从文件中获取,有时咱们还须要获取用户输出的内容。此时,咱们须要用到 read 命令,如下:

$ read

或者

$ read -p "answer me this" ANSWER

不带参数的 read 语句会读取用户输出并将其保留在 shell 变量 REPLY 中,这是 read 的最简模式。如果心愿 bash 在读取用户输出前先输入提示信息,能够应用 -p 选项。-p 之后的单词就是提示信息,如果想提供多个单词,能够将其援用起来。记住,要在提示信息结尾处加上标点符号或空格,因为光标会停在那里期待输出。-t 选项能够设置超时值。指定秒数达到后,不论用户是否输出,read 语句都会返回。咱们的示例同时用到了 -t 和 -p 选项,但你也能够独自应用 -t 选项。

下面的形式获取用户输出时会以明文回显,那实用明码输出么?

当咱们须要用户输出敏感信息时,须要禁止用户输出内容的回显。此时用 read 命令读取用户输出,须要加上一个非凡选项来敞开回显:

read -s -p "password:" PASSWD

printf "%b" "\n"

-s 选项通知 read 命令不要回显输出的字符(s 代表 silent),-p 选项指明下一个参数是提示信息,会在读取用户输出之前显示。从用户那里读取到的输出行保留在变量 $PASSWD 中。在 read 之后,咱们用 printf 输入了一个换行符。这里的 printf 不能少,因为 read -s 会敞开字符回显。如果禁止了回显性能,当用户按下回车键时,就不会回显换行符,后续输入就会和提示信息呈现在同一行。输入换行符会将光标带到下一行。

当然,咱们也能够抉择一行,如下:

read -s -p "password:" PASSWD ; printf "%b" "\n"

Shell 规范输入

如果无奈产生输入,那么软件也就没什么价值了,但长久以来,I/ O 始终是难缠的计算畛域之一。问题是有太多类型的输入, 向屏幕写入不同于向文件写入,向文件写入也不同于向磁带或闪存写入。所以,对于输入会产生一些问题,如下:

  • 软件开发人员是否要针对各种输出设备编写代码,甚至包含尚未创造的设施?
  • 写到哪个文件?程序怎么晓得是该写入代表终端窗口的文件、磁盘文件还是其余品种的文件?

显然,如果把这些事件都交给每个程序员是不合理的,所以这种事件留给 shell 就行了。

1、输入到终端 / 终端窗口

想要用 shell 命令产生一些简略的输入,应用内建命令 echo。命令行中的所有参数都会打印到屏幕上。

echo Please wait.

输入:

Please wait.

后果和在 bash 提示符(字符 $)后输出该命令雷同:

echo 是最简略的 bash 命令之一。该命令能够将参数输入到屏幕上。然而有几点须要记住:

  • 首先,shell 负责解析 echo 的命令行参数。将参数交给 echo 前,shell 会实现所有的替换、通配符匹配等操作。
  • 其次,在解析参数时,参数之间的空白字符会被疏忽,如下图:

shell 对参数间的空白字符没有太多限度,这通常是一种不错的个性。但对于 echo 来说,就有点烦人了。

  • 保留输入中的空白字符。将字符放入引号中就能够保留空白字符,如下图:

引号中的单词组成了 echo 命令的单个参数。该参数是一个字符串,shell 不会干预字符串的内容。实际上能够用单引号(”)明确通知 shell 不要干预字符串。

2、在输入中退出更多格局管制

应用内建命令 printf。例如:

printf '%s = %d\n' Lines $LINES
Lines = 24

或者:

$ printf '%-10.10s = %4.2f\n' 'Gigahertz' 1.92735

Gigahertz = 1.93

内建命令 printf 的行为和 C 语言中的同名库函数类似,其中第一个参数是格局管制字符串,之后的参数都依据格局标准(%)进行格式化。

% 和格局类型(本例为 s 或 f)之间的数字提供了额定的格式化细节。

对于浮点类型(f),第一个数字(批示符 4.2 中的 4)是整个字段的宽度。第二个数字(2)是应该在小数点右侧打印出的数位量。留神,后果会依照四舍五入解决。

对于字符串,第一个数字是字段的最大宽度,第二个数字是要输入的字符数量。依据须要,字符串会被截断(长于 max)或用空白填充(有余 min)。如果批示符 maxmin 雷同,那么就能够确保字符串依照该长度输入。批示符左侧的负号示意字符串向左对齐(在字段宽度内)。如果不应用负号,则字符串向右对齐

3、打消输入中的换行符

心愿输入中不蕴含 echo 默认生成的换行符。应用 printf,做法很简略,去掉格式化字符串开端的 \n 即可,如下图:

printf "%s %s" next prompt

如果是 echo,则应用 -n 选项:

$ echo -n prompt

因为 printf 的格局字符串(第一个参数)开端并没有换行符,所以命令行提示符($)呈现在了 printf 的输入之后。该个性在 shell 脚本中用途更大,你可能心愿在造成一整行前由多条语句逐局部输入,或者在读取输出前显示用户提醒。

换作 echo 命令(参见 15.6 节),打消换行符的办法有两种。

首先,-n 选项可能克制输入行尾的换行符。

另外,echo 命令还能够解决多种具备非凡含意的转义序列(如示意换行符的 \n),这些转移序列与 C 语言字符串中的相似。调用 echo 命令时加上 -e 选项。其中一种转义序列是 \C,它并不会输入什么字符,而是禁止在行尾输入换行符。如下图:

$ echo -e 'hi\c'

4、保留命令输入

如过想把命令输入保留在文件中,用 > 符号通知 shell 将输入重定向至文件,例如:

$ echo fill it up

fill it up

$ echo fill it up > file.txt

咱们来查看一下文件 file.txt 的内容,看看其中是否蕴含了命令的输入:

$ cat file.txt

fill it up

示例第一局部的第一行中呈现的 echo 命令蕴含了 3 个要输入的参数。第二行用 > 将这些输入保留到文件 file.txt 中,这就是看不

到 echo 输入的起因。

示例第二局部用 cat 命令显示文件内容。咱们能够看出,文件中蕴含的正是 echo 本该输入的内容。

cat 命令得名自一个较长的单词 concatenation(拼接)。该命令会将呈现在命令行上的文件的输入拼接在一起,如果你输出 cat

file1 file2 file3,那么这些文件的内容会一一发送到终端窗口。如果一个大文件被分成了两半,你也能够用 cat 将其复原原样(也就是将两局部拼接起来),这只需将输入保留到另一个文件中:

cat first.half second.half > mergeFile.txt

5、将输入保留到其余文件

如想要用重定向将输入保留到当前目录之外的其余地位,重定向输入时加上门路,如下:

echo some more data > /tmp/echo.out

或者:

echo some more data > ../../over.here

呈现在重定向符号(>)后的文件名其实就是路径名。如果没有任何限定局部,那么文件就会搁置在当前目录中。

如果文件名以斜线(/)起始是绝对路径名,此时文件会被搁置在文件系统层次结构(目录树)中以根目录起始的指定地位。

第二个例子中,咱们应用了相对路径名 ../../over.here,其中的.. 是一个指向父目录的非凡目录,存在于每个目录中。

6、将输入和谬误音讯发送到不同文件

心愿取得程序的输入,但不想输入被呈现的谬误音讯弄乱。要保留的谬误音讯混淆在程序输入中不容易找出,可将输入和谬误音讯重定向到不同文件,如下:

$ myprogram 1> messages.out 2> message.err

或者采纳更常见的办法:

$ myprogram > messages.out 2> message.err

shell 会创立两个输入文件。

第一个是 messages.out,程序 myprogram 的所有输入都会重定向到该文件。

第二个是 message.err,程序 myprogram 的所有谬误音讯都会重定向到 message.err。

在 1> 和 2> 中,数字示意文件 描述符。

  • 1 代表规范输入(STDOUT),
  • 2 代表规范谬误(STDERR)。
  • 0 代表规范输出(STDIN)。

如果不指定数字,则假设为 STDOUT。

7、将输入和谬误音讯发送到同一文件

利用重定向,咱们能够将输入或谬误音讯保留到独自的文件中,但如何将两者送往同一文件呢?用 shell 语法将规范谬误音讯重定向到和规范输入雷同的中央。

首选:

$ myprogram >& outfile

或者:

$ myprogram &> outfile

又或者老式且略繁缛的写法:

$ myprogram > outfile 2>&1

其中,myprogram 是筹备向 STDERR 和 STDOUT 生成输入的程序。

&> 和 >& 只是将 STDOUT 和 STDERR 发送到雷同中央的便捷写法。

8、追加输入

每次重定向输入,都会产生一个全新的输入文件。如果想要两次(或三次、四次……)重定向输入,同时又不想毁坏之前的输入,该怎么办呢?

在 bash 的重定向符号中,双大于号(>>)示意追加输入:

$ ls > /tmp/ls.out
$ cd ../elsewhere
$ ls >> /tmp/ls.out
$ cd ../anotherdir
$ ls >> /tmp/ls.out

如果存在同名文件,第一行中的重定向会将其截断,并将 ls 命令的输入保留在这个已被清空的文件中。

后两次调用 ls 时应用了双大于号(>>),示意向输入文件中追加内容,而不是笼罩其原有内容。

如果想要同时重定向谬误音讯(STDERR),能够将 STDERR 的重定向放在前面,如下所示:

ls >> /tmp/ls.out 2>&1

在 bash 4 中,你能够将这两个重定向合二为一:

$ ls &>> /tmp/ls.out

该命令会重定向 STDERR 和 STDOUT,并将两者追加到指定文件中。& 符号必须先呈现,且这 3 个字符之间不能有空格

9、抛弃输入

你有时不想将输入保留到文件中或者有时甚至不想看到输入。如咱们在查找某个文件时,疏忽那些没有权限的提醒,如下图:

此时,咱们能够将输入重定向到 /dev/null,如下所示:

$ find / -name myfile 2> /dev/null

其实,你能够将不想要的输入重定向到文件,而后再将其删除。但还有一个更简略的办法。Unix 和 Linux 零碎都存在一个非凡设施,该设施并非实在的硬件,而仅仅是一个位桶(bit bucket),咱们能够将不须要的数据都扔进去。它就是 /dev/null,十分实用于此类场景。写入其中的数据会被间接抛弃并不会占用磁盘空间,重定向很容易做到这一点。示例中,只有发往规范谬误的输入被抛弃了

本文由 传智教育博学谷 教研团队公布。

如果本文对您有帮忙,欢送 关注 点赞 ;如果您有任何倡议也可 留言评论 私信,您的反对是我保持创作的能源。

转载请注明出处!

退出移动版