首页IT科技shell的输入语句(Shell 标准输入和输出)

shell的输入语句(Shell 标准输入和输出)

时间2025-08-04 18:57:02分类IT科技浏览4435
导读:无论是要交给程序处理的数据,还是控制脚本的简单命令,都少不了输入和输出。程序要做的第一件事就是处理如同一阴一阳的“输入与输出”。...

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

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)                    。如果指示符 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                    ,非常适用于此类场景       。写入其中的数据会被直接丢弃并不会占用磁盘空间              ,重定向很容易做到这一点              。示例中,只有发往标准错误的输出被丢弃了

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

如果本文对您有帮助                    ,欢迎关注和点赞;如果您有任何建议也可留言评论或私信                    ,您的支持是我坚持创作的动力       。

转载请注明出处!

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
ps4奖杯可以转移吗知乎(玩什么游戏挣人民币-PS游戏奖杯值多少钱?你玩游戏赚了多少钱?) html基础教程视频(HTML零基础入门教程完整版)