Shell 标准输入和输出

news2025/1/23 4:31:30

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

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 提示符(字符 $)后输入该命令相同:

file

echo 是最简单的 bash 命令之一。该命令可以将参数输出到屏幕上。但是有几点需要记住:

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

file

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

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

file

引号中的单词组成了 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

file

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

$ echo -n prompt

file

因为 printf 的格式字符串(第一个参数)末尾并没有换行符,所以命令行提示符($)出现在了 printf 的输出之后。该特性在shell 脚本中用处更大,你可能希望在形成一整行前由多条语句逐部分输出,或者在读取输入前显示用户提示。

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

首先,-n 选项能够抑制输出行尾的换行符。

另外,echo 命令还可以处理多种具有特殊含义的转义序列(如表示换行符的 \n),这些转移序列与 C 语言字符串中的类似。调用 echo 命令时加上 -e 选项。其中一种转义序列是 \C,它并不会输出什么字符,而是禁止在行尾输出换行符。如下图:

$ echo -e 'hi\c'

file

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、丢弃输出

你有时不想将输出保存到文件中或者有时甚至不想看到输出。如我们在查找某个文件时,忽略那些没有权限的提示,如下图:

file
此时,我们可以将输出重定向到 /dev/null,如下所示:

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

其实,你可以将不想要的输出重定向到文件,然后再将其删除。但还有一个更简单的方法。Unix 和 Linux 系统都存在一个特殊设备,该设备并非真实的硬件,而仅仅是一个位桶(bit bucket),我们可以将不需要的数据都扔进去。它就是 /dev/null,非常适用于此类场景。写入其中的数据会被直接丢弃并不会占用磁盘空间,重定向很容易做到这一点。示例中,只有发往标准错误的输出被丢弃了

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

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

转载请注明出处!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/91560.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[ Linux ] 线程独立栈,线程分离,Linux线程互斥

目录 1.线程栈 1.1pthread_t 1.2用户级的线程id与内核LWP的对应关系 2.分离线程 2.1 pthread_detch 3.线程互斥 3.1互斥相关概念 3.2 互斥量mutex 3.3 售票系统案例验证共享变量会有问题 3.4 解决抢票问题 3.5互斥量的接口 3.5.1初始化互斥量 3.5.2 销毁互斥量 3…

MSF之ssh_login漏洞

ssh_login准备实操准备 目标机&#xff1a;windows xp 攻击机&#xff1a;kali 工具&#xff1a;metasploit framework 实操 先查看两机器的ip kali的ip为172.17.0.1 xp的ip为192.168.17.130 互相ping一下 没问题。 打开msf search ssh_login 爆出模块 use 0 show o…

vue项目打包流程与反向代理Nginx的使用

目录 前言 参考文章 正文 1.打包前的配置工作 做反向代理的原因&#xff08;Vue项目打包后Proxy失效的问题&#xff09;&#xff1a; 2.Nginx使用 前言 突发灵感想学习下打包&#xff0c;第一反应是学习webpack&#xff0c;翻找一通后发现用不着webpack&#xff0c;因为…

ORB-SLAM2 --- Tracking::UpdateLocalPoints函数

目录 1.函数作用 2.函数流程 3.code 4.函数解析 1.函数作用 更新局部关键点。先把局部地图清空&#xff0c;然后将局部关键帧的有效地图点添加到局部地图中。 2.函数流程 这是更新局部地图中的一个小函数&#xff0c;我们在Tracking::UpdateLocalKeyFrames更新了局部关键…

C++ Reference: Standard C++ Library reference: Containers: map: map: value_comp

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/map/value_comp/ 公有成员函数 <map> std::map::value_comp value_compare value_comp() const;返回值比较对象 返回一个比较对象&#xff0c;该对象可用于比较两个元素&#xff0c;以获得第一个元素的键…

Python 基础| Python 直接赋值、深拷贝和浅拷贝

先看这三个词的意思我觉得菜鸟的总结就很好 Python 直接赋值、浅拷贝和深度拷贝 | 菜鸟教程 直接赋值&#xff1a;其实就是对象的引用&#xff08;别名&#xff09;。 浅拷贝(copy)&#xff1a;拷贝父对象&#xff0c;不会拷贝对象的内部的子对象。 深拷贝(deepcopy)&#xf…

采购过程中会遇到的四种风险!如何管理和控制?

采购风险通常是指采购过程可能出现的一些意外情况&#xff0c;这些情况都会影响采购预期目标的实现。采购风险通常是由管理不善引起的&#xff0c;本文解释了采购过程中会遇到的四种风险&#xff0c;并介绍通过正确实施8Manage SRM采购管理系统&#xff0c;可以有效管理和控制它…

说说Python程序的执行过程

1. Python是一门解释型语言&#xff1f; 我初学Python时&#xff0c;听到的关于Python的第一句话就是&#xff0c;Python是一门解释性语言&#xff0c;我就这样一直相信下去&#xff0c;直到发现了*.pyc文件的存在。如果是解释型语言&#xff0c;那么生成的*.pyc文件是什么呢&…

工程项目管理的特点

工程项目管理是一种只关注工程项目的项目管理。它使用与任何其他类型的项目管理相同的标准方法和流程。这种专业化可能会吸引任何想要进入项目管理领域的具有工程背景的人。 工程项目管理与工程管理 工程管理侧重于对具有以下特点的工程师和工程任务的管理&#xff1a; 1、…

java UDP通信程序DatagramSocket数据接收

在查看本文前 您可以先看看我的文章 java UDP通信程序DatagramSocket数据发送 对UDP有一个基本的了解 然后这里我们就直接看代码了 我们先创建一个包 包下创建两个类 分别是 sendOut 发送类 参考代码如下 import java.io.IOException; import java.net.DatagramPacket; impo…

【Flutter 笔记系列 第 3 篇】如何正确对待Name source files using `lowercase with underscores`

相信很多安装了一些提示插件的小伙伴都遇见过 Name source files using lowercase with underscores flutter 提示 如下图 此时会有两种选择 1.能跑就行&#xff0c;无视它 2.好烦&#xff0c;我也没干什么怎么就提示不规范了。 3.一定是哪里出了问题&#xff0c;我要找到…

高通Ride软件开发包使用指南(8)

高通Ride软件开发包使用指南&#xff08;8&#xff09;6.9跟踪6.10 基础感知延迟分析6.10.1生成CSV6.9跟踪 用户可以使用Google Chrome中的跟踪功能分析代码的执行浏览器以下步骤中的示例显示如何分析Foundation SDK相机知觉 必须启用相关日志条目&#xff0c;因为跟踪使用SD…

说说Spring事件发布机制

文章目录前言一、 使用到事件发布机制的源码二、Springboot启动过程中用到的部分事件三、Springboot中的监听器四、自定义事件源&#xff0c;事件监听器和事件发布器4.1 目录结构4.2 事件源4.3 事件监听器4.4 事件帮助器4.4.1 事件发布帮助接口4.4.2 事件发布帮助接口实现类4.4…

运维就业现状怎么样?技能要求高吗?

运维至少需要知道哪些知识才可以去面试&#xff1f; 有一个答案对这一话题的解读非常深入&#xff0c;体系化的分析了所需掌握的技术、工作内容、性质及可发展的方向等等&#xff0c;今天特别分享给大家&#xff0c;按照这个发展&#xff0c;运维则已不需担心就业、薪酬等问题了…

MySQL -2 指令

客户端SQL指令记录&#xff1a; -- 针对 数据库和针对数据表 &#xff08;一&#xff09;数据库 1. 查看当前所有数据库&#xff1a;show databases; 2. 创建数据库&#xff1a;create database 数据库名 DEFAULT CHARSET utf8 COLLATE utf8_general_ci; 3. 删除数据库&#…

【一建、一造经验分享】一建挺难的,要坚持才能得到

标签&#xff1a;【备考四年】、【2020全科通过一建】、【2021全科通过一造】 思绪回到2017年7月份&#xff0c;软考-项目管理师出成绩了&#xff0c;很幸运我通过了。由于通信行业及单位认可“以考代评”&#xff0c;所以我最先下手的是软考高级&#xff0c;拿证等同于高工。在…

程序员核心------详解调试(2)

所爱隔山海&#xff0c;山海皆可平&#xff0c;所念皆星河&#xff0c;星河不可及。 上课&#xff01; 接着上节课讲的调试&#xff08;1&#xff09;&#xff0c;本节课进一步讲解调试(2). 文章目录1.调试实例讲解&#xff08;2&#xff09;校招笔试题 2.如何写出好的&#…

【大数据技术Hadoop+Spark】MapReduce概要、思想、编程模型组件、工作原理详解(超详细)

MapReduce是Hadoop系统核心组件之一&#xff0c;它是一种可用于大数据并行处理的计算模型、框架和平台&#xff0c;主要解决海量数据的计算&#xff0c;是目前分布式计算模型中应用较为广泛的一种。 一、MapReduce核心思想 MapReduce的核心思想是“分而治之”。所谓“分而治之…

猿人学APP第一题

抓包分析 copy CURL 转 requests代码 def app1():import requestsheaders {"Accept-Language": "zh-CN,zh;q0.8","User-Agent": "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; Nexus 6P Build/OPM1.171019.011) AppleWebKit/534.30 (K…

KT6368A蓝牙芯片的MTU的说明以及如何加快BLE传输速率

目录 一、蓝牙MTU的简介 二、详细的方法说明以及测试 三、KT6368A提升ble传输速率方法 BLE传输带宽主要跟两个要素有关&#xff1a; 通信周期和每个通信点可传输的数据量。 1.通信周期&#xff1a; 安卓手机一般可支持到10ms&#xff0c;苹果一般可支持到15ms 2.每个通信点…