无论是要交给程序处理的数据,还是操控脚本的简略指令,都少不了输入和输出。程序要做的榜首件事便是处理如同一阴一阳的“输入与输出”。
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变量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)。假如指示符 max 和 min 相同,那么就能够确保字符串依照该长度输出。指示符左边的负号表明字符串向左对齐(在字段宽度内)。假如不运用负号,则字符串向右对齐
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,十分适用于此类场景。写入其间的数据会被直接丢掉并不会占用磁盘空间,重定向很容易做到这一点。示例中,只有发往规范过错的输出被丢掉了
本文由
传智教育博学谷
教研团队发布。假如本文对您有帮助,欢迎
重视
和点赞
;假如您有任何建议也可留言评论
或私信
,您的支撑是我坚持创作的动力。转载请注明出处!