大家好,欢迎来到IT知识分享网。
输入输出重定向
输入重定向是把文件导入到命令中,而输出重定向则是把原本要输出到屏幕上的数据信息写入到指定文件中。在日常的学习和工作中,相较于输入重定向,我们使用输出重定向的频率更高,所以又将输出重定向分为标准输出重定向和错误输出重定向两种不同的技术,以及清空写入与追加写入两种模式。
标准输入重定向(STDIN,文件描述符为0) : 默认从键盘输入,也可从其它文件或命令输入。 标准输出重定向(STDOUT, 文件描述符为1):默认输出到屏幕。 错误输出重定向(STDERR, 文件描述符为2):默认输出到屏幕。
我们分别查看两个文件的属性信息,其中第二个文件是不存在的,虽然针对这两个文件的操作都分别会在屏幕上输出一些数据信息,但这两个操作的差异其实很大:
root@ubuntu-1:~/workroom/c_test/test_dir$ touch test root@ubuntu-1:~/workroom/c_test/test_dir$ ls test root@ubuntu-1:~/workroom/c_test/test_dir$ root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l test -rw-rw-r-- 1 root root 0 Aug 24 23:32 test root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l xxx ls: cannot access 'xxx': No such file or directory
在上述命令中,名为test的文件是存在的,输出信息是该文件的一些相关权限,所有者,所属组,文件大小及修改时间等信息,这也是该命令的标准输出信息。而名为xxx的第二个文件是不存在的,因此在执行ls命令之后显示的报错信息也是该命令的错误输出信息。要想把原本输出到屏幕上的数据转而写入到文件当中,就要区别对待这两种输出信息了。
对于输入重定向来讲,用到的符号及其作用:
符号 |
作用 |
命令 < 文件 |
将文件作为命令的标准输入 |
命令 << 分界符 |
从标准输入中读入,直到遇见分界符才停止 |
命令 < 文件1 > 文件2 |
将文件1作为命令的标准输入并将标准输出到文件2 |
对于输入重定向来讲,用到的符号及其作用:
符号 |
作用 |
命令 > 文件 |
将标准输出重定向到一个文件中,清空原有文件的数据。 |
命令2 > 文件 |
将错误输出重定向到一个文件中,清空原有文件的数据。 |
命令 >> 文件 |
将标准输出重定向到一个文件中,追加到原有内容的后面。 |
命令 2>> 文件 |
将错误输出重定向到一个文件中,追加到原有内容的后面。 |
命令 >> 文件 2>&1 或命令 &>> 文件 |
将标准输出与错误输出共同写入到文件中,追加到原有内容的后面。 |
对于重定向的标准输出模式,可以省略文件描述符1不写,而错误输出模式的文件描述符2是必须要写的。
root@ubuntu-1:~/workroom/c_test/test_dir$ man strcpy > readme.txt root@ubuntu-1:~/workroom/c_test/test_dir$ ls readme.txt test root@ubuntu-1:~/workroom/c_test/test_dir$ cat readme.txt STRCPY(3) Linux Programmer's Manual STRCPY(3) NAME strcpy, strncpy - copy a string SYNOPSIS #include <string.h> char *strcpy(char *dest, const char *src); char *strncpy(char *dest, const char *src, size_t n); DESCRIPTION The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy. Beware of buffer overruns! (See BUGS.)
接下来尝试输出重定向技术中的覆盖写入与追加这两种不同模式带来的变化。首先通过覆盖写入模式向readme.txt文件写入一行数据(该文件中包含上一个实验的man命令信息),然后再通过追加写入模式向文件再写入一次数据,其命令如下:
root@ubuntu-1:~/workroom/c_test/test_dir$ echo "Welcome to Linux" > readme.txt root@ubuntu-1:~/workroom/c_test/test_dir$ echo "Learning Linux" >> readme.txt root@ubuntu-1:~/workroom/c_test/test_dir$ cat readme.txt Welcome to Linux Learning Linux
虽然都是输出重定向技术,但是不同命令的标准输出和错误输出还是有区别的。例如查看当前目录中某个文件的信息,这个以test文件为例,因为这个文件是真实存在的,因此使用标准输出即可将原本要输出到屏幕的信息写入到文件中,而错误的输出重定向则依然把信息输出到了屏幕上。
root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l test -rw-rw-r-- 1 chengy chengy 0 Aug 24 23:32 test root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l test > stderr.txt root@ubuntu-1:~/workroom/c_test/test_dir$ cat stderr.txt -rw-rw-r-- 1 root root 0 Aug 24 23:32 test root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l test 2> stderr.txt -rw-rw-r-- 1 root root 0 Aug 24 23:32 test
如果想把命令的报错信息写入到文件,该怎么操作呢?当用户在执行一个自动化的Shell脚本时,这个操作会特别有用,而且特别实用,因为它可以把整个脚本执行过程中的报错信息都记录到文件中,便于安装后的排错工作。
root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l xxx ls: cannot access 'xxx': No such file or directory root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l xxx > stderr.txt ls: cannot access 'xxx': No such file or directory root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l xxx 2> stderr.txt root@ubuntu-1:~/workroom/c_test/test_dir$ cat stderr.txt ls: cannot access 'xxx': No such file or directory
接下来使用输入重定向把readme.txt文件导入wc -l 命令,统计一下文件中的内容行数。
root@ubuntu-1:~/workroom/c_test/test_dir$ wc -l < readme.txt 2
root@ubuntu-1:~/workroom/c_test/test_dir$ cat readme.txt | wc -l 2
管道命令符
管道命令符的作用是把前一个命令原本要输出到屏幕的正常数据当作是后一个命令的标准输入。
通过匹配关键词/sbin/nologin找出了所有被限制登录系统的用户。
找出被限制登录用户的命令是grep "/sbin/nologin" /etc/passwd; 统计文本行数的命令是wc -l;
现在要做的就是把搜索命令的输出值传递给统计命令,即把原本要输出到屏幕的用户信息列表再交给wc命令作进一步的加工,因此只需要把管道符放到两条命令之间即可。
root@ubuntu-1:~/workroom/c_test/test_dir$ grep "/sbin/nologin" /etc/passwd | wc -l 17
我们可以将它套用到其它不同的命令上,比如用翻页的形式查看/etc目录中的文件列表及属性信息:
在修改用户密码时,通常都需要输入两次密码以进行确认,这在编写自动化脚本时将成为一个非常致命的缺陷。通过把管道符和passwd命令的 –stdin 参数相结合,我们可以用一条命令来完成密码重置操作:
# echo "test" | passwd --stdin root Changing password for user root. passwd: all authentication tokens updated successfully.
当然,大家千万不要误以为管道命令符只能在一个命令组合中使用一次,我们完全可以这样使用:”命令A | 命令B | 命令C”。
命令行的通配符
假设想要批量查看所有硬件文件的相关权限属性,一种方式是这样的:
root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l /dev/sda sda sda1 sda2 sda5 root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l /dev/sda brw-rw---- 1 root disk 8, 0 Aug 18 23:42 /dev/sda root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l /dev/sda1 brw-rw---- 1 root disk 8, 1 Aug 18 23:42 /dev/sda1 root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l /dev/sda2 brw-rw---- 1 root disk 8, 2 Aug 18 23:42 /dev/sda2 root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l /dev/sda5 brw-rw---- 1 root disk 8, 5 Aug 18 23:42 /dev/sda5 root@ubuntu-1:~/workroom/c_test/test_dir$
通配符就是通用的匹配信息的符号,比如星号(*)代表匹配零个或多个字符,问号(?)代表匹配单个字符,中括号内加上数字[0-9]代表匹配0~9之间的单个数字的字符,而中括号内加上字母[abc]则是代表匹配a,b,c三个字符中的任意一个字符。
下面我们就来匹配所有在/dev目录中且以sda开头的文件:
root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l /dev/sda* brw-rw---- 1 root disk 8, 0 Aug 18 23:42 /dev/sda brw-rw---- 1 root disk 8, 1 Aug 18 23:42 /dev/sda1 brw-rw---- 1 root disk 8, 2 Aug 18 23:42 /dev/sda2 brw-rw---- 1 root disk 8, 5 Aug 18 23:42 /dev/sda5
如果只想查看文件名为sda开头,但是后面还紧跟其它某一个字符的文件的相关信息,就需要用到问号来进行通配了
root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l /dev/sda? brw-rw---- 1 root disk 8, 1 Aug 18 23:42 /dev/sda1 brw-rw---- 1 root disk 8, 2 Aug 18 23:42 /dev/sda2 brw-rw---- 1 root disk 8, 5 Aug 18 23:42 /dev/sda5
使用[0-9] 来匹配0~9之间的单个数字,也可以用[135]这样的方式仅匹配这三个指定数字中的一个,若没有匹配到,则不会显示出来:
root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l /dev/sda[0-9] brw-rw---- 1 root disk 8, 1 Aug 18 23:42 /dev/sda1 brw-rw---- 1 root disk 8, 2 Aug 18 23:42 /dev/sda2 brw-rw---- 1 root disk 8, 5 Aug 18 23:42 /dev/sda5 root@ubuntu-1:~/workroom/c_test/test_dir$ ls -l /dev/sda[135] brw-rw---- 1 root disk 8, 1 Aug 18 23:42 /dev/sda1 brw-rw---- 1 root disk 8, 5 Aug 18 23:42 /dev/sda5
常用的转义字符
常用的转义字符如下所示:
反斜杠(\) : 使反斜杠后面的一个变量变为单纯的字符串。 单引号('') : 转义其中所有的变量为单纯的字符串。 双引号(""):保留其中的变量属性,不进行转义处理。 反引号(``) : 把其中的命令执行后返回的结果。
我们先定义一个名为PRI的变量并赋值为5,然后输出双引号括起来的字符串与变量信息:
root@ubuntu-1:~/workroom/c_test/test_dir$ PRI=3 root@ubuntu-1:~/workroom/c_test/test_dir$ echo "pri is $PRI" pri is 3
接下来,我们希望能够输出”pri is $3″, 要想让第一个”#34;作为符号输出,那么就需要使用反斜杠(\)来进行转义,将这个命令提取符转义成单纯的文本,去除其特殊功能。
root@ubuntu-1:~/workroom/c_test/test_dir$ echo "pri is $PRI" pri is 24924PRI
root@ubuntu-1:~/workroom/c_test/test_dir$ PRI=6 root@ubuntu-1:~/workroom/c_test/test_dir$ echo "pri is \$PRI" pri is $6
而如果只需要某个命令的输出值时,可以像命令这样,将命令用反引号括起来,达到预期的效果。例如,将反引号与uname -a命令结合,然后使用echo命令来查看本机的Liunx版本和内核信息:
root@ubuntu-1:~/workroom/c_test/test_dir$ echo `uname -a` Linux ubuntu-1 4.4.0-62-generic #83-Ubuntu SMP Wed Jan 18 14:10:15 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
重要的环境变量
为了通过环境变量帮助Linux系统构建为用户提供服务的工作运行环境,需要数百个变量协同工作才能完成。简单来说,命令在Linux中的执行分为4个步鄹:
- 判断用户是否以绝对路径或相对路径的方式输入命令(如/bin/ls),如果是的话则直接执行。
- Linux系统检查用户输入的命令是否为”别名命令”,即用一个自定义的命令名称来替换
原来的命令名称,可以用alias命令来创建一个属于自己的命令别名,格式为”alias 别名=命令”。若要取消一个命令别名,则是用unalias命令,格式为”unalias 别名”。
root@ubuntu-1:~/workroom/c_test/test_dir$ alias rm alias rm='rm -fr ' root@ubuntu-1:~/workroom/c_test/test_dir$ ls readme.txt stderr.txt test chengy@ubuntu-1:~/workroom/c_test/test_dir$ rm -i test rm: remove regular empty file 'test'? n chengy@ubuntu-1:~/workroom/c_test/test_dir$ ls readme.txt stderr.txt test
- Bash 解释器判断用户输入的是内部命令还是外部命令。内部命令是解释器内部的指令,会被直接执行;而用户在绝大部分时间输入的是外部命令,这些命令交由步骤4继续处理。可以使用”type 命令名称” 来判断用户输入的命令是内部命令还是外部命令。
- 系统在多个路径中查找用户输入的命令文件,而定义这些路径的变量叫作PATH,可以简单地把它理解成解释器的小助手,作用是告诉Bash解释器待执行的命令可能存放的位置。PATH是由多个路径值组成的变量,每个路径值之间用冒号间隔,对这些路径的增加和删除操作将影响到Bash解释器对Linux命令的查找。
root@ubuntu-1:~/workroom/c_test/test_dir$ echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/otn_toolchain/toolchain/host/usr/bin:/opt/toolchain/aarch64/bin
Linux 系统中最重要的几个环境变量
变量名称 |
作用 |
HOME |
用户的主目录 |
SHELL |
用户在使用的Shell 解释器名称 |
HISTSIZE |
输出的历史命令记录条数 |
HISTFILESIZE |
保存的历史命令记录条数 |
|
邮件保存路径 |
LANG |
系统语言,语系名称 |
RANDOM |
生成一个随机数字 |
PS1 |
Bash解释器的提示符 |
PATH |
定义解释器搜索用户执行命令的路径 |
EDITOR |
用户默认的文本编辑器 |
root@ubuntu-1:~/workroom/c_test/test_dir$ echo $RANDOM 28773 root@ubuntu-1:~/workroom/c_test/test_dir$ echo $EDITOR root@ubuntu-1:~/workroom/c_test/test_dir$ echo $PS1 \[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ root@ubuntu-1:~/workroom/c_test/test_dir$ echo $LANG en_US.UTF-8 root@ubuntu-1:~/workroom/c_test/test_dir$ echo $MAIL /var/mail/root root@ubuntu-1:~/workroom/c_test/test_dir$ echo $HOME /home/root root@ubuntu-1:~/workroom/c_test/test_dir$ echo $SHELL /bin/bash root@ubuntu-1:~/workroom/c_test/test_dir$ echo $HISTSIZE 1000 root@ubuntu-1:~/workroom/c_test/test_dir$ echo $HISTFILESIZE 2000
Linux 作为一个多用户多任务的操作系统,能够为每个用户提供独立的,合适的工作运行环境,因此,一个相同的变量会因为用户身份的不同而具有不同的值。
其实变量是有固定的变量名与用户或系统设置的变量值两部分组成的,我们完全可以自行创建变量,来满足工作需求。例如设置一个名称为WORKDIR的变量,方便用户更轻松地进入一个层次较深的目录:
root@ubuntu-1:~/workroom/c_test/test_dir$ pwd /home/test/workroom/c_test/test_dir root@ubuntu-1:~/workroom/c_test/test_dir$ WORKDIR=/home/test/workroom/c_test/test_dir root@ubuntu-1:~/workroom/c_test/test_dir$ cd $WORKDIR root@ubuntu-1:~/workroom/c_test/test_dir$ cd .. root@ubuntu-1:~/workroom/c_test$ cd .. root@ubuntu-1:~/workroom$ cd $WORKDIR root@ubuntu-1:~/workroom/c_test/test_dir$
但是,这样的变量不具有全局性,作用范围有限,默认情况下不能被其它用户使用,如果工作需要,可以使用export命令将其提升为全局变量,这样其它用户也就可以使用它了。
root@ubuntu-1:~/workroom$ cd $WORKDIR root@ubuntu-1:~/workroom/c_test/test_dir$export WORKDIR
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/83966.html