17.Linux Shell输入输出流管理

文章目录

  • Linux Shell输入输出流管理
    • 1)标准文件描述符
    • 2)脚本中重定向输出
      • 临时重定向
      • 永久重定向
      • 自定义输出重定向
    • 3)重定向输入
    • 4)支持读写的文件描述符
    • 5)关闭文件描述符
    • 6) 列出打开的文件描述符及关闭文件描述符
    • 7)输出同时发送到显示器和日志文件


欢迎访问个人网络日志🌹🌹知行空间🌹🌹


Linux Shell输入输出流管理

目前对于普通用户来说,接触到最多的Linux Shell输出的方法有两个,一个是显示到显示器上,一个是将输出重定向到文件中。不过,目前的方式,只能二选一,要么将shell全部输出到显示器上,要么将shell输出全部保存到文件中,如果想将一部分输出到显示上一部分记录到文件中,那么该如何实现呢?如何用标准的Linux输入和输出系统来将脚本输出导向特定位置呢?

1)标准文件描述符

Linux系统将每个对象当作文件处理。Linux用文件描述符来标识每个文件对象。文件描述符是一个非负整数,可以唯一标识会话中打开的文件。每个进程一次最多可以有九个文件描述符。出于特殊目的,bash shell保留了前三个文件描述符(0, 1, 2)。这三个特殊文件描述符作为标准的文件描述符会处理脚本的输入和输出。

文件描述符缩写描述
0STDIN标准输入
1STDOUT标准输出
2STDERR标准错误

STDIN文件描述符代表shell的标准输入。对终端界面来说,标准输入是键盘。shellSTDIN文件描述符对应的键盘获得输入,在用户输入时处理每个字符。

许多bash命令能接受 STDIN 的输入,尤其是没有在命令行上指定文件的话。

当在命令行上只输入 cat 命令时,它会从 STDIN 接受输入。输入一行, cat 命令就会显示出一行。

$ cat
this is a line
this is a line

在使用输入重定向符号( < )时,Linux会用重定向指定的文件来替换标准输入文件描述符。它会读取文件并提取数据,就如同它是键盘上键入的。

可以通过 STDIN 重定向符号强制 cat 命令接受来自另一个非 STDIN 文件的输入:

cat < file
this is a line

**STDOUT文件描述符代表shell的标准输出。**在终端界面上,标准输出就是终端显示器。shell的所有输出(包括shell中运行的程序和脚本)会被定向到标准输出中,也就是显示器。

通过输出重定向符号,通常会显示到显示器的所有输出会被shell重定向到指定的重定向文件。

$ ls -alh > test.log
# cat test.log
# 总用量 12K
# drwxrwxr-x 2 rob rob 4.0K 1月   5 23:28 .
# drwxr-xr-x 6 rob rob 4.0K 1月   5 23:28 ..
# -rw-rw-r-- 1 rob rob    3 1月   5 23:28 1.txt
# -rw-rw-r-- 1 rob rob    0 1月   5 23:28 test.log

也可以用>>符号将数据追加到某个文件

$ who >> test.log
# cat test.log
# 总用量 12K
# drwxrwxr-x 2 rob rob 4.0K 1月   5 23:28 .
# drwxr-xr-x 6 rob rob 4.0K 1月   5 23:28 ..
# -rw-rw-r-- 1 rob rob    3 1月   5 23:28 1.txt
# -rw-rw-r-- 1 rob rob    0 1月   5 23:28 test.log
# lx       :1           2024-01-02 21:11 (:1)

当命令生成错误消息时,shell并不能将错误消息重定向到输出重定向文件

$ ls -alh rob > test.log
# ls: 无法访问 'rob': 没有那个文件或目录

test.log文件创建成功了,只是里面是空的。shell对于错误消息的处理是跟普通输出分开的。

STDERR文件描述符用来处理错误消息STDERR文件描述符代表shell的标准错误输出。shellshell中运行的程序和脚本出错时生成的错误消息都会发送到这个位置。

尽管分配给它们的文件描述符值不同,默认情况下, STDERR 文件描述符会和 STDOUT 文件描述符指向同样的地方,譬如显示器,但STDERR 并不会随着 STDOUT 的重定向而发生改变。

要重定向错误输出,只需要在使用重定向符号时定义 STDERR 文件描述符就可以了STDERR 文件描述符被设成 2,可以选择只重定向错误消息。

$ ls -al rob 2> test.log
cat test.log 
# ls: 无法访问 'rob': 没有那个文件或目录

用这种方法,shell会只重定向错误消息,正常 STDOUT 输出仍然会发送到默认的 STDOUT 文件描述符,也就是显示器。

要同时重定向错误和正常输出,必须用两个重定向符号

$ ls -al rob  test.log 2> test.log 1>out.log
cat test.log 
# ls: 无法访问 'rob': 没有那个文件或目录
cat out.log 
# -rw-rw-r-- 1 rob rob 52 1月   5 23:44 test.log

也可以将 STDERRSTDOUT 的输出重定向到同一个输出文件。为此bash shell提供了特殊的重定向符号&>

$ ls -al rob  test.log &> test.log
# ls: 无法访问 'rob': 没有那个文件或目录
# -rw-rw-r-- 1 rob rob 52 1月   5 23:47 test.log

当使用 &> 符时,命令生成的所有输出都会发送到同一位置,包括数据和错误。为了避免错误信息散落在输出文件中,相较于标准输出,bash shell自动赋予了错误消息更高的优先级。

2)脚本中重定向输出

在脚本中通过重定向STDOUTSTDERR 文件描述符就可以在多个位置生成输出了。

临时重定向

可以将单独的一行输出重定向到 STDERR

#!/bin/bashecho error message >&2
echo normal message

执行,

$ ./redirect.sh 2>erro.log
# normal message
$ cat erro.log
# error message

在上面的例子中,会发现error message这句被记录到erro.log文件中了,这正是因为在echo语句后面加了>&2将输出内容重定向了STDERR了。在运行脚本时重定向了STDERR,脚本中所有导向 STDERR 的文本都会被重定向。

永久重定向

像上面那样,一句一句的重定向,如果需要输出的内容多的话,就会变的很麻烦了。这时,可以用 exec 命令在shell脚本运行时重定向某个特定文件描述符。

exec 1>testout

这个语句在shell脚本中可以将STDOUT重定向到文件testout中,这时就不会显示到显示器上了。

#!/bin/bashexec 1>testout
echo "This is a test of redirecting all output"
echo "from a script to another file."

执行,

$ ./redirect.sh
$ cat testout
# This is a test of redirecting all output
# from a script to another file.

可以在脚本执行过程中重定向 STDOUT

#!/bin/bashexec 2>testerrorecho start of script
echo STDOUT to log fileexec 1>testoutecho log to file
echo log to error file >&2

执行,

$ ./redirect.sh
# start of script
# STDOUT to log file
$ cat testout 
# log to file
$ cat testerror
# log to error file

这个脚本示例中值得注意的是,exec 2>testerror语句将STDERR重定向到了文件testerror中,这时后面再将输出重定向到STDERR中时>&2,错误信息会被记录到testerror文件中

不过上面的操作也有个问题,那就是一旦将STDOUT重定向到文件testout中就没办法再恢复输出到屏幕上了。接下来会介绍怎样才能实现重定向的恢复。

自定义输出重定向

前面介绍的是3个标准的文件描述符的重定向,除此之外每个进程还支持自定义6个打开的文件描述符。

可以用 exec 命令来给输出分配文件描述符。

#!/bin/bash
exec 3>test3outecho log to screen
echo log to test3out >&3
echo log back to screen 

执行,

$ ./redirect.sh
# log to screen
# log back to screen
$ cat test3out
# log to test3out

以上就是自定义了输出文件描述符3到文件test3out中,上面会创建新文件test3out,也可以不创建新文件,而使用追加的方式,

exec 3>>test13out

可以分配另外一个文件描述符给标准文件描述符,这样就可以恢复已重定向的文件描述符了

#!/bin/bashexec 3>&1
exec 1>test13outecho log to test13out fileexec 1>&3
echo log to screen

执行,

$ ./redirect.sh
# log to screen
$ cat test13out 
# log to test13out file

上面的例子,是先将文件描述符3重定向到STDOUT,再将STDOUT重定向到文件test13out,输出结束后又将文件描述符1重定向到文件描述符3也就是STDOUT上,这样就可以将输出恢复到屏幕上了,有点类似暂存变量的意思。

3)重定向输入

默认的STDIN是用户从键盘输入,exec 命令允许你将 STDIN 重定向到Linux系统上的文件中。

exec 0< testfile

这个命令会告诉shell它应该从文件 testfile 中获得输入,而不是 STDIN

filename=$1
exec 0< $filename 
count=1while read line
doecho "Line #$count: $line"count=$[ $count + 1 ]
done

执行,

$ cat testfile 
# error message
# new line
$ ./redirect.sh testfile
# Line #1: error message
# Line #2: new line

read 命令读取用户在键盘上输入的数据。将 STDIN 重定向到文件后,
read 命令试图从 STDIN 读入数据时,它会到文件去取数据,而不是键盘。

可以用和重定向输出文件描述符同样的办法重定向输入文件描述符

#!/bin/bashexec 6<&0
testfile=$1
exec 0< $testfile
count=1
while read line
doecho "Line #$count: $line"count=$[ $count + 1 ]
doneexec 0<&6
read -n1 -p "Are you sure? " answer
echo
case $answer inY|y) echo "Good.";;N|n) echo "Sorry.";;
esac

执行,

$ ./rediect.sh
# Line #1: error message
# Line #2: new line
# Are you sure? Y
# Good.

这里先创建了文件描述符6作为STDIN的重定向,又将STDIN重定向到了testfile,最后又利用6恢复了STDIN,这和前面介绍的STDOUT的重定向与恢复基本类似。

4)支持读写的文件描述符

以打开单个文件描述符来作为输入和输出,即用同一个文件描述符对同一个文件进行读写。用这种方法时,要特别小心,因为是对同一个文件进行数据读写,shell会维护一个指明在文件中的当前位置的内部指针,任何读或写都会从文件指针上次的位置开始,如果操作不小心会导致文件内容的读写错位。

支持输入输出的文件描述符的创建方式是使用<>符号,

exec 3<> testfile

支持输入输出文件描述符的一个例子,

#!/bin/bashexec 3<> testfileread line <&3
echo "The first line: $line"echo "line2" >&3

执行,

$ cat testfile
# error message
# new line
$ ./redirect.sh
# The first line: error message
$ cat testfile
# error message
# line2
# ne

这个例子中,read line <&3定义了从文件描述符3中读取一行输入,这时文件指针就指向了第二行的开始位置,重定向输入到&3中时,line2\n会被记录到testfile文件第二行开始的位置,并覆盖掉原来的内容。最后就得到了上面展示的结果。

5)关闭文件描述符

shell会在脚本退出时自动关闭创建的新的输入或输出文件描述符。有时需要在脚本结束前手动关闭文件描述符,对应的操作是将它重定向到特殊符号 &-

exec 3>&-

尝试使用已关闭的文件描述符时会报错,

# ./redirect.sh: 第 11 行: echo: 写错误: 错误的文件描述符

当然也可以手动关闭标准输入输出文件描述符,关闭后同样无法再使用它们。

在关闭文件描述符后,如果随后在脚本中又打开了同一个输出文件,shell
会用一个新文件来替换已有文件,会覆盖掉原来的内容。

6) 列出打开的文件描述符及关闭文件描述符

lsof 命令会列出整个Linux系统打开的所有文件描述符。因为它会向非系统管理员用户提供Linux系统的信息,因此这是个功能颇有争议。该命令会产生大量的输出。它会显示当前Linux系统上打开的每个文件的有关信息。这包括后台运行的所有进程以及登录到系统的任何用户。

lsof支持大量的参数来筛选,最常用的如-p指定进程ID-d指定要显示的文件描述符编号,-u指定用户名或用户ID,-a选项用来对其他选项的结果执行布尔 AND 运算。

要想知道进程的当前PID,可以用特殊环境变量 $$

$ echo $$
# 75485

执行,

$ lsof -a -d 0,1,2 -u rob# COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
# sh      75484  rob    0u   CHR  136,3      0t0    6 /dev/pts/3
# sh      75484  rob    1u   CHR  136,3      0t0    6 /dev/pts/3
# sh      75484  rob    2u   CHR  136,3      0t0    6 /dev/pts/3
# bash    75485  rob    0u   CHR  136,3      0t0    6 /dev/pts/3
# bash    75485  rob    1u   CHR  136,3      0t0    6 /dev/pts/3
# bash    75485  rob    2u   CHR  136,3      0t0    6 /dev/pts/3
# lsof    97492  rob    0u   CHR  136,3      0t0    6 /dev/pts/3

执行,

$ lsof -a -d 0,1,2 -u rob -p $$
# COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
# bash    75485  rob    0u   CHR  136,3      0t0    6 /dev/pts/3
# bash    75485  rob    1u   CHR  136,3      0t0    6 /dev/pts/3
# bash    75485  rob    2u   CHR  136,3      0t0    6 /dev/pt

lsof 的默认输出:

描述
COMMAND正在运行的命令名的前9个字符
PID进程的PID
USER进程属主的登录名
FD文件描述符号以及访问类型( r 代表读, w 代表写, u 代表读写)
TYPE文件的类型( CHR 代表字符型, BLK 代表块型, DIR 代表目录, REG 代表常规文件)
DEVICE设备的设备号(主设备号和从设备号)
SIZE如果有的话,表示文件的大小
NODE本地文件的节点号
NAME文件名

有时候想阻止命令输出,可以将 STDERR/STDOUT 重定向到一个叫作null文件的特殊文件,null文件跟它的名字很像,文件里什么都没有。shell输出到null文件的任何数据都不会保存,全部都被丢掉了。Linux系统上null文件的标准位置是/dev/null。重定向到该文件的数据都会被丢掉,不会显示。

ls -al > /dev/null

**使用这个重定向的情况一般有两种,一种是将脚本放到后台后不希望其再输出,另外一个用来快速清空文件
**

cat /dev/null > testfile

7)输出同时发送到显示器和日志文件

将输出同时发送到显示器和日志文件,不用将输出重定向两次,只要用特殊的 tee 命令就行。tee 命令相当于管道的一个T型接头。它将从 STDIN 过来的数据同时发往两处。一处是STDOUT ,另一处是 tee 命令行所指定的文件名:

$ date | tee testfile
# Sun Oct 19 18:56:21 EDT 2014
cat testfile
# Sun Oct 19 18:56:21 EDT 2014

默认情况下, tee 命令会在每
次使用时覆盖输出文件内容。如果想将数据追加到文件中,必须用 -a 选项。

date | tee -a testfile

不过,tee命令只能记录STDOUT不能记录STDERR,如果要显示的同时记录STDERR,需要自己手动实现,linux没有提供可以直接使用的命令。


可以结合mktemp命令更好的管理脚本输出的日志文件,关于mktemp命令的介绍可以参考Linux Shell创建临时文件


欢迎访问个人网络日志🌹🌹知行空间🌹🌹


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

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

相关文章

大模型实战笔记02——大模型demo

大模型实战笔记02——大模型demo 1、大模型及InternLM模型介绍 2、InternLM-Chat-7B智能对话Demo 3、Lagent智能体工具调用Demo 4、浦语灵笔图文创作理解Demo 5、通用环境配置 注 笔记图片均为视频截图 笔记课程视频地址&#xff1a;https://www.bilibili.com/video/BV1Ci4y1…

基于 IP 多播的网络会议程序(2024)

1.题目描述 局域网 IP 多播程序&#xff0c;设计一个图形界面的网络会议程序&#xff08;实现文本多播方式即可&#xff09;。 2.演示Demo 3.参考代码 广播发送代码 //服务端 #include <winsock2.h> #include <iostream> #include <list>#pragma comment(l…

顶顶通呼叫中心中间件通过队列外呼拨打另一个sip并且放音(mod_cti基于FreeSWITCH)

介绍 顶顶通呼叫中心中间件通过队列外呼拨打另一个sip并且放音 一、添加acl 打开ccadmin->点击配置文件->点击acl.conf->在</list>后面添加一条图中的信息->muqi是我自己设置的名字你们可以修改为自己需要的名字->添加好了点击提交XML->在运维调试点…

如何理解链接(Linking)这一编译过程中的步骤

在理解链接&#xff08;Linking&#xff09;这一编译过程中的步骤之前&#xff0c;有必要了解编译器的整体工作流程。编译器通常经历以下几个阶段&#xff1a; 预处理&#xff08;Preprocessing&#xff09;&#xff1a;处理源代码文件中的预处理指令&#xff0c;如 #include 指…

Redis概览

Redis存储是Key-Value结构的数据&#xff0c;其中Key是字符串类型&#xff0c;Value有5种常见的数据类型 字符串 String 哈希 hash 列表 list 集合 set 有序集合 sorted set / zset 各种数据类型的特性 字符串操作命令 : ● SET ke…

v8 pwn利用合集

文章目录 前置知识JS Object 相关Ignition 相关JIT - turboFan 相关starCTF2019 OOB【越界读写map字段】googleCTF2018 jit【浮点数精度丢失导致越界读写】数字经济线下 Browser【Object::toNumber中callback导致的越界写】前置知识 JS Object 相关 V8 中的对象表示 ==> 基…

LeetCode 2125. 银行中的激光束数量【数组,遍历】1280

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

深入理解 Vue.js 中的 `h` 函数:虚拟 DOM 创建指南

Vue.js 是一个用于构建用户界面和单页应用程序的渐进式 JavaScript 框架。它的核心概念之一是虚拟 DOM&#xff0c;这是实际 DOM 的轻量级副本&#xff0c;Vue 使用它来优化对网页的更新。为了操作虚拟 DOM&#xff0c;Vue 提供了一个通常被称为 h 函数的方法。这个函数对于理解…

大模型查询工具助手之股票免费查询接口

新浪股票免费查询接口 股票研究的实践中需要查询股票市场接口&#xff0c;百度搜索大多链接都要收费或者注册。 记得新浪股票以前是免费查询&#xff0c;但现在遇到了小问题。 决策引擎专栏&#xff1a; Falcon构建轻量级的REST API服务 决策引擎-利用Drools实现简单防火墙策…

vue 用 h() 函数创建 Vnodes

目录 前言一、h() 函数的基本使用方式二、h() 函数的进阶使用方式1、条件渲染2、列表渲染3、事件4、使用插槽 前言 Vue 提供了一个 h() 函数用于创建 vnodes。 h() 是 hyperscript 的简称——意思是“能生成 HTML (超文本标记语言) 的 JavaScript”。 const vnode h(div, /…

技术学习周刊第 1 期

2018 年参与过 1 年的 ARTS 打卡&#xff0c;也因为打卡有幸加入了 MegaEase 能与皓哥&#xff08;左耳朵耗子&#xff09;共事。时过境迁&#xff0c;皓哥已经不在了&#xff0c;自己的学习梳理习惯也荒废了一段时间。 2024 年没给自己定具体的目标&#xff0c;只要求自己好好…

电话号码信息收集工具:PhoneInfoga | 开源日报 No.137

sundowndev/phoneinfoga Stars: 11.2k License: GPL-3.0 PhoneInfoga 是一个用于扫描国际电话号码的信息收集框架&#xff0c;它允许用户首先收集基本信息 (如国家、地区、运营商和线路类型)&#xff0c;然后使用各种技术来尝试找到 VoIP 提供商或识别所有者。该工具与一系列必…

[足式机器人]Part2 Dr. CAN学习笔记-动态系统建模与分析 Ch02-7二阶系统

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-动态系统建模与分析 Ch02-7二阶系统 1. 二阶系统对初始条件的动态响应 Matlab/Simulink - 2nd Order Syetem Response to IC2. 二阶系统的单位阶跃响应 2nd Order System Unit Step Response3. 二…

copilot在pycharm的应用

Copilot在PyCharm中的应用 一、引言 随着人工智能技术的飞速发展&#xff0c;AI在编程领域的应用也越来越广泛。Copilot&#xff0c;作为一款由微软开发的AI编程助手&#xff0c;已经引起了广大开发者的关注。它利用深度学习技术&#xff0c;通过分析大量开源代码&#xff0c…

Linux-v4l2框架

框架图 从上图不难看出&#xff0c;v4l2_device作为顶层管理者&#xff0c;一方面通过嵌入到一个video_device中&#xff0c;暴露video设备节点给用户空间进行控制&#xff1b;另一方面&#xff0c;video_device内部会创建一个media_entity作为在media controller中的抽象体&a…

unity中0GC优化方案《zstring》

文章目录 序言简介GC带来的问题性能瓶颈玩家体验受损 使用方式 序言 游戏开发秉承遇到好东西要分享&#xff0c;下面介绍zstring&#xff0c;感谢作者开源无私奉献 源码地址&#xff1a;https://github.com/871041532/zstring 简介 GC带来的问题 性能瓶颈 GC暂停主线程执行…

LaTeX中常用的字母及符号

收集 LaTeX 中常用的字母、符号。 字体字形设置 命令实例说明\fbox LaTeX \fbox{LaTeX} LaTeX​加边框\boxed L a T e X \boxed{LaTeX} LaTeX​斜体加边框\mathbf L a T e X \mathbf{LaTeX} LaTeX加粗\boldsymbol L a T e X \boldsymbol{LaTeX} LaTeX斜体加粗 希腊字母 符号…

docker 安装elasticsearch、kibana、cerebro

安装步骤 第一步安装 docker 第二步 拉取elasticsearch、kibana、cerebro 镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:7.10.2 docker pull docker.elastic.co/kibana/kibana:7.10.2 docker pull lmenezes/cerebro:latest第三步、创建 容器 创建e…

设计模式之中介者模式【行为型模式】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档> 学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某…

[Kafka集群] 配置支持Brokers内部SSL认证\外部客户端支持SASL_SSL认证并集成spring-cloud-starter-bus-kafka

目录 Kafka 集群配置 准备 配置流程 Jaas(Java Authentication and Authorization Service )文件 zookeeper 配置文件 SSL自签名 启动zookeeper集群 启动kafka集群 spring-cloud-starter-bus-kafka 集成 Kafka 集群配置 准备 下载统一版本Kafka服务包至三台不同的服…