跟我一起学 Liunx 重定向和管道符

重定向

  • 标准输入重定向(STDIN,文件描述符为0) - 默认从键盘输入,也可从其他文件或命令中输入
  • 标准输出重定向(STDOUT,文件描述符为1) - 默认输出到屏幕
  • 错误输出重定向(STDERR,文件描述符为2) - 默认输出到屏幕

输出重定向

  • 输出重定向:将执行的命令所输出的内容,重定向到指定的文件内
  • 输出重定向符号分为以下几种
    • 正确输出重定向
      • 命令 > 文件 - 正确输出重定向(覆盖)
        • 命令 1> 文件 - 重定向中的标准输出模式,可以省略文件描述符1不写
      • 命令 >> 文件 - 正确输出重定向(追加)
    • 错误输出重定向
      • 命令 2> 文件 - 错误输入重定向(覆盖)
        • 错误输出模式的文件描述符2是必须要写的
      • 命令 2>> 文件 - 错误输入重定向(追加)
    • 共同输出重定向
      • 命令 &> 文件 - 正确和错误输出重定向到同一个文件(覆盖)
        • 另一种写法
          • 命令 > 文件 2>&1
      • 命令 &>> 文件 - 正确和错误输出重定向到同一个文件(追加)
        • 另一种写法
          • 命令 >> 文件 2>&1
          • 2>&1 是一个固定的格式,是覆盖还是追加,取决于前面的重定向是覆盖还是追加
正确输出重定向

将原本要显示在屏幕上的内容(命令返回的状态码为0),输出到指定的文件中

一定要注意自己是需要追加还是覆盖,将文件内容覆盖,相当于自己把文件内容删了,毕竟 Linux 一切皆文件,执行重定向操作前,要有备份的习惯,误操作覆盖了,也能还原原来的内容

  • 利用正确输出重定向生成一个新的文件
  • 当我们不使用 > study.txt 这一部分,只使用 echo 'hello world' ,回车后,会在显示器上返回 hello world 这一段字符
  • 完成后,执行 cat study.txt 就可以看到文件的内容是 hello world
  • 但是如果存在 study.txt 这个文件时,多次执行下面的命令,文件内永远都只有 hello world 这一段内容
echo 'hello world' > study.txt
  • 将正确输出重定向追加到指定的文件
  • 执行了下面的命令后,我们查看(cat study.txt) 文件时,发现里面有两行内容,一行是前面覆盖 重定向写入的 hello world ,另一行就是这个时候插入的 good luck, have fun 这段内容
  • 每执行一次下面的命令,study.txt 文件内就会增加一行 good luck, have fun
  • 如果执行上面的 echo 'hello world' > study.txt ,那 study.txt 文件内就只有 hello world 一行内容了
echo 'good luck, have fun' >> study.txt
  • 配合 <<EOF 实现静态写入多行内容
    • 一般写入多行内容,都会使用 vim 或者 vi 这类文本编辑器去操作,但是写 shell 就需要去规避这一类的人为干预,重定向配合 <<EOF 就是一个很好的方法
    • <<EOFEOF 为结尾来结束文件内容的写入

同样也是要注意是覆盖还是插入的方式

  • 覆盖写入
cat <<EOF > study.txt
this is a test1
this is a test2
this is a test3
EOF
  • 追加写入
cat <<EOF >> study.txt
this is a test1 too
this is a test2 too
this is a test3 too
EOF

多次执行就可以看出效果和区别

错误输出重定向

将原本要显示在屏幕上的内容(命令返回的状态码为非0),输出到指定的文件中

同样也是要注意需要使用的是覆盖还是追加

  • 本机 PATH 变量没有 whoami.bak 这个命令
  • 使用 which whoami.bak ,屏幕上会输出 /usr/bin/which: no whoami.bak in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin)
    • 假设我写脚本,需要判断一个命令是否存在,但我有强迫症,我不想看到这些报错,我只想知道有没有,可以使用下面的方式,将错误输出重定向到 /dev/null 文件内,这个文件是一个黑洞文件,所有进入到这个文件的文件或目录,都会不复存在(比如 mv xxx.txt > /dev/null 相当于执行了rm -f 命令)
which whoami.bak 2> /dev/null
  • 将上面的命令,重定向到 study.txt 文件内
    • 分别为覆盖和追加,相信通过上面的操作,大家已经心里有了13数了
which whoami.bak 2> study.txt
which whoami.bak 2>> study.txt
共同输出重定向

将正确的和错误的输出都重定向到同一个文件内

同样也是要注意需要使用的是覆盖还是追加

  • 同样引用上面的案例,我需要去判断当前的 PATH 变量里面有没有我需要的命令,如果没有,我就执行其他的操作
  • $? 是用来判断上一条命令执行的状态为成功(返回状态码0)还是不成功(返回状态码为非0
  • 重定向操作是成功的,但是命令实际是属于错误输出的,此时的 $? 返回的状态码为非0
  • 命令操作是成功的,但是重定向操作时不正常的,$? 返回的状态码也是非0
    • 比如重定向的文件名称和目录名称一样,就会返回 Is a directory 的报错
# || 在 shell 中作为判断使用,表示的是 '或者' ,|| 前后只需要有一个命令可以正确执行即可
## whoami.bak 不存在,因此会返回 true
which whoami.bak &> /dev/null || echo "true"
## whoami 存在,因此不会返回 true
which whoami &> /dev/null || echo "true"
敲黑板
  • 无论是哪种输出重定向,一定要注意指向的文件,如果执行的文件是二进制文件,那二进制文件就会变成普通文件,可以通过 file 命令去比较
  • 重定向对目录类型的文件操作会返回 Is a directory 的报错
  • 输出重定向千万不要对块设备操作,比如磁盘,会导致数据被覆盖,后果很严重
  • 举个离(例)子(子) [离谱的例子]

备份一个 whoami 命令来玩,不能直接玩,不然命令就废了

cp /usr/bin/whoami{,.bak}

先查看 whoami.bak 文件的属性

file /usr/bin/whoami.bak

可以看到,是一个 ELF 文件,属于 executable 可执行文件

/usr/bin/whoami.bak: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0cd50214a1dcf60ac187526884bb621ede7ef83a, stripped

咱们重定向一些内容给 whoami.bak

追加的情况下,不会影响文件本身的类型

echo 'this is a test' >> /usr/bin/whoami.bak

覆盖的情况下,文件本身的类型就会变为 ASCII text 文本文件

echo 'this is a test' > /usr/bin/whoami.bak

所以输出重定向所指定的文件一定要注意了,不要指定错了,不然后悔都来不及

输入重定向

  • 输入重定向:从文件内将内容重定向给命令

  • 这个例子比较奇葩,因为可以直接使用 cat study.txt 命令,这里是用来做一个理解使用的例子

cat < study.txt
  • 一般像 mysql 需要导入 sql 文件,就可以使用输入重定向的方式
mysql -u<user_name> -p<user_passworld> -h<mysql_host> -P<mysql_port> < xxx.sql

输入输出重定向

  • 输入输出重定向:将文件的内容输入重定向给命令后,将命令输出的内容重定向到指定的文件内

  • 命令 < 文件1 > 文件2 - 将文件1的输入重定向输出到文件2

  • 同样是一个不太恰当的例子,主要是用来理解思路的

    • 将 study.txt 文件内容输入cat 命令,再将 cat 命令输出的内容,输出到 study.txt.bak 文件内
    • 实际使用 cat study.txt > study.txt.bak 就可以了
cat < study.txt > study.txt.bak

字符串重定向

  • 字符串重定向:将字符串输入重定向给命令

  • 命令 <<< "字符串" - 字符串输入重定向

  • 以上的输入输出重定向,都是需要针对文件的情况下操作的,但是在写脚本的时候,遇到一些变量需要被引用,但是写 echo ${xxx} | awk '{print $1}' 又觉得没有13格,这个时候,就轮到字符串重定向上场了

先定义一个变量

test='hello world'

当我只想要得到 hello 这一个内容,我又不想用 echo,那就可以用字符串重定向的方式

# --color 参数是高亮过滤到的内容,有的 linux 发行版的 grep 命令默认不带这个参数
grep --color hello <<< ${test}
# 过滤 hello,我只要输出 hello
grep -o hello <<< ${test}
# awk 的形式
awk '{print $1}' <<< ${test}

管道符

进程管道

  • | 表示管道符,将管道符前面操作的输出转交给管道符后面的来操作和处理

  • 同样是一个奇葩的例子,用来便于理解

    • 实际直接使用 grep root /etc/passwd 就可以了
cat /etc/passwd | grep root
  • 123 木头人,不许说话不许动
    • 通过 echo 将 sleep 3 输出,然后交给 bash 执行
    • 实际直接使用 sleep 3 就可以了
echo "sleep 3" | bash

三通管道

  • tee 是一个命令,加上管道符,可以变成三通管道,将三通管道前面操作的输出做一个副本
    • 三通管道和正确输出重定向的区别在于,正确输出重定向不会在屏幕上显示输出的内容,直接写入指定的文件内;而三通管道会输出到屏幕上,并写入到指定的文件内
    • 三通管道和错误输出重定向的区别在于,错误输出重定向不会屏幕上显示输出的内容,直接写入指定的文件内;而三通管道会输出到屏幕上,并不会将错误内容写入到文件内,文件内容会被空内容覆盖
    • 可以使用 -a 参数,追加到指定的文件内
cat study.txt | tee study-bak.txt

参数传递

  • xargs 命令表示参数传递

  • Linux xargs 命令

    • xargs(英文全拼: eXtended ARGuments)是给命令传递参数的一个过滤器,也是组合多个命令的一个工具
    • xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据
    • xargs 也可以将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行
    • xargs 默认的命令是 echo,这意味着通过管道传递给 xargs 的输入将会包含换行和空白,不过通过 xargs 的处理,换行和空白将被空格取代
    • xargs 是一个强有力的命令,它能够捕获一个命令的输出,然后传递给另外一个命令
    • 之所以能用到这个命令,是由于很多命令不支持 | 进程管道来传递参数
  • xargs 参数

    • -a - file 从文件中读入作为 stdin
    • -e - flag ,注意有的时候可能会是-E,flag必须是一个以空格分隔的标志,当xargs分析到含有flag这个标志的时候就停止
    • -p - 当每次执行一个argument的时候询问一次用户
    • -n - num 后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用所有的
    • -t - 表示先打印命令,然后再执行
    • -i - 或者是-I,这得看linux支持了,将xargs的每项名称,一般是一行一行赋值给 {},可以用 {} 代替
    • -r - no-run-if-empty 当xargs的输入为空的时候则停止xargs,不用再去执行了
    • -s - num 命令行的最大字符数,指的是 xargs 后面那个命令的最大命令行字符数
    • -L - num 从标准输入一次读取 num 行送给 command 命令
    • -l - 同 -L
    • -d - delim 分隔符,默认的xargs分隔符是回车,argument的分隔符是空格,这里修改的是xargs的分隔符
    • -x - exit的意思,主要是配合 -s 使用
    • -P - 修改最大的进程数,默认是 1,为 0 时候为as many as it can
  • 又是一个不太恰当的例子,主要用于理解

    • echo 命令无法获取通过 | 进程管道 传递的内容
ls | echo
  • 使用 | xagrs 后可以获取到 ls 传递的内容
ls | xargs echo
  • 多行内容通过 xargs 变成单行内容
    • 继续使用上面用到的 study.txt 文件
cat study.txt | xargs
  • 常用的 -i 或者 -I 参数,配合 {} 来指定参数传递的指定位置
    • 在当前路径下的 .txt 文件后面加上 -bak 的后缀
ls *.txt | xargs -i mv {}{,-bak}

{} 的位置决定了参数传递的位置

ls *.txt* | xargs -i echo "{} is a test"
ls *.txt* | xargs -i echo "test for {}"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值