Shell 命令通常有输入输出。默认从标准输入设备(stdin
)获取输入,结果输出到标准输出设备(stdout
)显示。通常:
- 标准输入设备:键盘
- 标准输出设备:终端,即显示器
Shell 命令运行时都会打开三个文件:
- 标准输入文件(
stdin
):文件描述符0
,从stdin
读取数据 - 标准输出文件(
stdout
):文件描述符1
,向stdout
输出数据 - 标准错误文件(
stderr
):文件描述符2
,向stderr
流中写入错误信息
但是输入输出也可来自其它地方,这就是输入输出重定向。
1 输出重定向
1.1 标准输出重定向
将命令的标准输出写到文件里:
command 1> log_a.txt # 直接输出,覆盖之前的文件
command 1>> log_b.txt # 添加到之前文件的后面
需要注意command
后面的1>
和1>>
,在1
和>
或>>
之间是没有空格的。如果按照下面写法,则1
是command
的参数。
command 1 > log_a.txt
由于默认是标准输出,也可以去掉1
:
command > log_a.txt
command >> log_a.txt
1.2 标准错误重定向
标准错误的文件描述符是2
:
command 2>log_a.txt
command 2>>log_a.txt
标准错误中的2
一定要放置在>
或者>>
前,且中间没有空格。
1.3 同时重定向
command >log.txt 2>&1 # 把标准错误和标准输出同时输出到一个文件
command 1>log_a.txt 2>log_b.txt # 将两者输出到不同的文件
输出文件合并
n >& m # 将输出文件 m 和 n 合并。
1.4 特殊的/dev/null
/dev/null
是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。(看起来像个黑洞。)但/dev/null
文件非常有用,将命令的输出重定向到它,会起到禁止输出的效果。
command > /dev/null
command 2> /dev/null
command > /dev/null 2>&1
2 输入重定向
可以理解和输出重定向相反,输入来自于文件。
2.1 输入重定向
标准输入是键盘,其实也可以从文件输入:
shell_command < filea.txt # 将filea.txt的内容作为标准输入
2.2 输入文件合并
n <& m #将输入文件 m 和 n 合并。
2.3 Here document
就是在命令行中输入多行文字:
command << delimiter
document
delimiter
它将两个delimiter
之间的内容(document
) 作为输入传递给 command
:
- 结尾的
delimiter
一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。 - 开始的 delimiter 前后的空格会被忽略掉。
也可将Here Document
用在脚本中:
#!/bin/bash
cat << EOF
This is a simple lookup program for good (and bad) restaurants
in Cape Town.
EOF
3 输入输出重定向
同时处理输入和输出的情况。
command < file1 >file2 # 把file1作为标准输入,file2作为标准输出
4 管道命令
4.1 |
命令
管道命令(|
)将一个命令的输出,转换为另外一个命令的输入。
常见情形如筛选文件夹(如.
)中包含特定名字(如y
)的文件:
ls . | grep y
这里就使用了管道命令|
,将ls .
的输出转换为grep
命令的输入。管道命令可以连续使用,则是ls . | grep y | grep -v x
:筛选出所有包含y
但是不包含x
的文件。
管道命令会开启新的线程来执行。比如说grep y
就和ls .
并不在同一个线程。
4.2 xargs
对输出进行操作
管道命令的输出并不一定满足下一个命令的输入,有时候需要对管道命令进行一些操作再传递为输入,此时就需要xargs
命令。xargs
(ex
tended arg
uments
),可以实现:
- 参数处理
- 从文件中读取信息作为输入
xargs
后需要接后续处理的命令,如果没有显示指定,则默认为echo
。虽然xargs
的输入可以包含空格和换行,但是经过echo
的处理,都会变成空格。
ls . | ls -l
这里报错原因是ls -l
的输入不对,需要用xargs
命令来转换一下:
ls . | xargs ls -l
常见参数如下,为了说明问题,这里构建了例子文件。
➜ cat x.txt
shell_00.md
shell_01.md
shell_02.md
shell_03.md
shell_04.md
shell_05.md
-a
xx 从文件获取输入
➜ xargs -a x.txt file
shell_00.md: Unicode text, UTF-8 text
shell_01.md: Unicode text, UTF-8 text
shell_02.md: Unicode text, UTF-8 text
shell_03.md: Unicode text, UTF-8 text
shell_04.md: Unicode text, UTF-8 text
shell_05.md: Unicode text, UTF-8 text
-p
每执行一个参数时询问一次用户,需要输入y
+回车键 或者yes
+回车键表示确定,单独输入回车键表示不执行:
➜ xargs -a x.txt -p file
file shell_00.md shell_01.md shell_02.md shell_03.md shell_04.md shell_05.md?...yes
shell_00.md: Unicode text, UTF-8 text
shell_01.md: Unicode text, UTF-8 text
shell_02.md: Unicode text, UTF-8 text
shell_03.md: Unicode text, UTF-8 text
shell_04.md: Unicode text, UTF-8 text
shell_05.md: Unicode text, UTF-8 text
-n
num,命令执行时一次用的参数个数,默认用所有的,如果已经有的参数超过了这个数目,则会分行执行。
➜ xargs -a x.txt -p -n 2 file
file shell_00.md shell_01.md?...yes
shell_00.md: Unicode text, UTF-8 text
shell_01.md: Unicode text, UTF-8 text
file shell_02.md shell_03.md?...yes
shell_02.md: Unicode text, UTF-8 text
shell_03.md: Unicode text, UTF-8 text
file shell_04.md shell_05.md?...yes
shell_04.md: Unicode text, UTF-8 text
shell_05.md: Unicode text, UTF-8 text
-t
先打印具体执行的命令,再执行-i
或-I
,将xargs
的每项名称,一般是一行一行赋值给{}
,可以用{}
代替-r
no-run-if-empty 当 xargs 的输入为空的时候则停止 xargs,不再去执行-L
或-l
num 从标准输入一次读取 num 行送给后面的命令
➜ xargs -a x.txt -t -L 2 file
file shell_00.md shell_01.md
shell_00.md: Unicode text, UTF-8 text
shell_01.md: Unicode text, UTF-8 text
file shell_02.md shell_03.md
shell_02.md: Unicode text, UTF-8 text
shell_03.md: Unicode text, UTF-8 text
file shell_04.md shell_05.md
shell_04.md: Unicode text, UTF-8 text
shell_05.md: Unicode text, UTF-8 text
需要和前面-n
做一个区别。这里指的是输入的行数,而-n
指的是输出的参数的个数。
-d
delimeter 分隔符,默认分隔符是空格,是 xargs 的输入的分隔
➜ echo "ambmcmdm" | xargs -dm
a b c d
-e
或-E
flag, e 是 end 的意思,flag 必须是一个以空格分隔的标志,当 xargs 分析到含有 flag 这个标志的时候就停止-s
num 命令行的最大字符数,xargs 后面那个命令的最大命令行字符数-x
exit,配合-s
使用-P
修改最大的进程数,默认是 1,为 0 时候尽可能多。
4.3 tee
命令
tee
读取标准输入的数据,并将其内容输出成文件。常见参数如下:
-a
或--append
附加到既有文件的后面,而非覆盖它。-i
或--ignore-interrupts
忽略中断信号。
总结
本文介绍了 Shell 中输入输出重定向,以及通过管道命令来实现前一命令的输出作为后一命令的输入。以此介绍了xargs
和tee
命令。