如何在 Linux 中使用 shell 重定向和管道操作文件
处理文件、目录、命令行环境和文档是系统管理员必备的知识。了解文件描述符及其与这些主题的关系可以提高您的系统管理员技能。本文介绍了三个标准 Linux 文件描述符,用于通过 shell 重定向和管道来操作文件。
什么是文件描述符?
简单来说,文件描述符是整数(数字),在 Linux 系统中充当打开文件(或其他 I/O 资源)的唯一标识符。请记住,在类 Unix 系统中,“一切都是文件描述符或进程”(引用Linus Torvalds 的话),甚至“一切都可以有一个文件描述符”(引用Neil Brown 的话)。了解所谓的三个标准文件描述符或标准流的工作原理非常重要且有用,因为所有进程都使用这些通道进行输入和输出操作。
为了避免本文太长,我建议您更详细地阅读有关流和文件描述符、描述符和流以及端口和文件描述符的 GNU 文档。以下是这些概念的快速而简单的概述。
考虑下面的图片:
用户与系统的交互是通过标准输入 (stdin)(即通道/流 0,通常使用键盘)输入的。然后,通过交互式 shell 执行的任何命令都会连接到运行 shell 的文本终端,并通过标准输出 (stdout)(即通道/流 1,如果正常)或标准错误 (stderr)(即通道/流 2,如果不正确)发送输出。stdout 通常是显示器显示的终端。还有其他通道和流(3 及以上),任何进程都可以使用,并且没有默认的输入或输出。
Shell I/O 重定向
您可以通过利用重定向和管道来操纵和更改这三个基本文件描述符的默认行为。例如,您可以将输入从键盘更改为文件。您可以将消息重定向到文件,而不是在终端中获取消息,甚至可以丢弃错误消息,而不是在显示器上看到它们。您还可以同时将输出重定向到终端和文件。您甚至可以将命令输出处理为另一个命令的输入。
There are three redirectors to work with: >
, >>
, and <
. The following information describes each one:
Redirection with >
command > file
: Sends standard output to<file>
command 2> file
: Sends error output to<file>
command 2>&1
: Sends error output to standard outputcommand > file 2>&1
: Sends standard output and the error output to a filecommand &> file
: Sends standard output and the error output to a filecommand 2>&1 > file
: Sends error output to standard input and the standard input to a file
Append with >>
command >> file
: Appends standard output to a filecommand 2>> file
: Appends error output to a filecommand >> file 2>&1
: Appends standard output and error output to a filecommand &>> file
: Appends standard output and error output to a filecommand 2>&1 >> file
: Sends error output to standard input and appends standard input to a file
Redirect with <
command < input
: Feeds a command input from<input>
command << input
: Feeds a command or interactive program with a list defined by a delimiter; this is known as a here-document (heredoc)command <<< input
: Feeds a command with<input>
; this is known as a here-string
Shell I/O examples
Here are some examples of using each operator in the order presented above.
Redirect the standard output for a given command to a file:
$ echo "Enable Sysadmin" > myfile
$ cat myfile
Enable Sysadmin
Redirect error output for a given command to a file:
$ ls /root 2> myfile
$ cat myfile
ls: cannot open directory '/root': permission denied
Redirect error output for a given command to the standard output, the terminal:
$ ls /root 2>&1
ls: cannot open directory 'root/': Permission denied
Redirect both standard output and error output for a given command to a file:
$ find /usr -name ls > myfile 2>&1
$ cat myfile
/usr/bin/ls
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
find: '/usr/libexec/initscripts/legacy-actions/auditd': Permission denied
$
$ find /usr -name ls &> myfile
$ cat myfile
/usr/bin/ls
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
find: '/usr/libexec/initscripts/legacy-actions/auditd': Permission denied
Redirect error output for a given command to the standard output, the terminal, and the standard output for the same command to a file:
$ find /usr -name ls 2>&1 > myfile
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
find: '/usr/libexec/initscripts/legacy-actions/auditd': Permission denied
$ cat myfile
/usr/bin/ls
Append the standard output for a given command to an existing file (if the file doesn’t exist, it creates it, just as the >
operator does):
$ cat myfile
/usr/bin/ls
$ echo "Enable Sysadmin" >> myfile
$ cat myfile
/usr/bin/ls
Enable Sysadmin
Append the error output for a given command to an existing file:
$ ls /root 2>> myfile
$ cat myfile
/usr/bin/ls
Enable Sysadmin
ls: cannot open directory '/root': Permission denied
Append both the standard output and the error output for a given command to an existing file:
$ find /usr -name cd >> myfile 2>&1
$ cat myfile
/usr/bin/ls
Enable Sysadmin
ls: cannot open directory '/root': Permission denied
/usr/bin/cd
/usr/lib/.build-id/cd
/usr/share/X11/xkb/symbols/cd
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
find: '/usr/libexec/initscripts/legacy-actions/auditd': Permission denied
$
$ find /usr -name cd &>> myfile
$ cat myfile
/usr/bin/ls
Enable Sysadmin
ls: cannot open directory '/root': Permission denied
/usr/bin/cd
/usr/lib/.build-id/cd
/usr/share/X11/xkb/symbols/cd
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
Redirect the error output for a given command to the standard output, the terminal, and append the standard output for the same command to an existing file:
$ find /usr -name cd 2>&1 >> myfile
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
find: '/usr/libexec/initscripts/legacy-actions/auditd': Permission denied
$ cat myfile
/usr/bin/ls
Enable Sysadmin
ls: cannot open directory '/root': Permission denied
/usr/bin/cd
/usr/lib/.build-id/cd
/usr/share/X11/xkb/symbols/cd
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
find: '/usr/libexec/initscripts/legacy-actions/auditd': Permission denied
/usr/bin/cd
/usr/lib/.build-id/cd
/usr/share/X11/xkb/symbols/cd
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
Feed a command with a nonstandard input, in this case, a file:
$ sort < myfile
/usr/bin/cd
/usr/bin/cd
/usr/bin/cd
/usr/bin/ls
/usr/bin/.build-id/cd
/usr/bin/.build-id/cd
/usr/bin/.build-id/cd
/usr/share/X11/xkb/symbols/cd
/usr/share/X11/xkb/symbols/cd
/usr/share/X11/xkb/symbols/cd
Enable Sysadmin
find: '/usr/libexec/initscripts/legacy-actions/auditd': Permission denied
find: '/usr/libexec/initscripts/legacy-actions/auditd': Permission denied
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/polkit-1/rules.d': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
find: '/usr/share/selinux/targeted/default/active': Permission denied
ls: cannot open directory '/root': Permission denied
Feed a command with a non-standard dynamic input, in this case, the input is a list of strings needing a token delimiter, and also redirect the result to a file:
$ cat << EOF
> Enable
> Sysadmin
> EOF
Enable
Sysadmin
$
$ cat << EOF > myfile
> Enable
> Sysadmin
> EOF
$ cat myfile
Enable
Sysadmin
$
Feed a command with a nonstandard input, in this case, a string, with no need for a token delimiter:
$ read a b <<< "Sysadmin Enable"
$ echo $b $a
Enable Sysadmin
Shell piping
In Linux, a pipeline is a mechanism that allows two or more processes to be combined or executed concurrently. That means the process output will be handled as an input for the next one, and so on. It's not called a pipeline for nothing: It refers to the concept of a process flow being channeled through a pipe from a source to a destination.
The following image gives an example of how it works:
The operator used is the vertical bar on your keyboard, the |
symbol. To "pipe" one command to another, separate the commands with this operator. It looks like this:
$ command1 | command2 | command3
Shell piping examples
Here are some examples:
Feed the grep
input command with the output of the cat
command:
$ cat /etc/passwd | grep localuser
localuser:×:1000:1000:Local User:/home/localuser/bin/bash
Redirect the standard output of the printf
command to a file and then feed the sort
command with the same newly created content into the file:
$ printf "Sysadmin\nEnable\n" > myfile | sort myfile
Enable
Sysadmin
Check the available RAM with the free
command, filter the result for swap information with the grep
command, and then use awk
to cut only the the "total" column from the output to be exhibited:
$ free -h | grep Swap | awk '{print $2}'
1.0Gi
$
There are many other possibilities. You just need to understand your needs and use the pipeline accordingly to get what you want from these combinations.
Wrap up
As a sysadmin, it's crucial for you to understand the concepts behind file descriptors and know how to use the available operators to execute redirections and pipelining in a shell such as Bash so that you can manipulate the standard inputs and outputs on your system. This skill gives you a complete set of resources and possibilities to streamline, facilitate, improve, and automate the administration of your system. I hope this article aids you in understanding this topic, helps your Linux certification path, and adds to your general sysadmin knowledge.