十一、输入/输出重定向
在 Shell 脚本中,输入/输出重定向是一种强大的功能,允许你将命令的输入和输出从默认的标准输入(stdin)、标准输出(stdout)和标准错误(stderr)重定向到文件或其他命令。
1. 标准输出重定向 (>
和 >>
)
>
:将命令的标准输出重定向到文件。如果文件已存在,内容会被覆盖。
echo "Hello, World!" > output.txt
将 Hello, World!
写入 output.txt
文件。如果 output.txt
已存在,原有内容会被覆盖。
>>
:将命令的标准输出追加到文件末尾。如果文件不存在,会创建新文件。
echo "Hello again!" >> output.txt
将 Hello again!
追加到 output.txt
文件的末尾,而不会覆盖原有内容。
2. 标准错误重定向 (2>
和 2>>
)
2>
:将命令的标准错误重定向到文件。如果文件已存在,内容会被覆盖。
ls /nonexistent_directory 2> error.txt
如果目录不存在,错误信息会被写入 error.txt
文件。
2>>
:将命令的标准错误追加到文件末尾。如果文件不存在,会创建新文件。
ls /another_nonexistent_directory 2>> error.txt
错误信息会被追加到 error.txt
文件的末尾。
3. 同时重定向标准输出和标准错误 (&>
和 &>>
)
&>
:将标准输出和标准错误都重定向到文件。如果文件已存在,内容会被覆盖。
ls /nonexistent_directory &> output_and_error.txt
无论命令成功还是失败,输出和错误信息都会被写入 output_and_error.txt
文件。
&>>
:将标准输出和标准错误都追加到文件末尾。如果文件不存在,会创建新文件。
ls /another_nonexistent_directory &>> output_and_error.txt
输出和错误信息会被追加到 output_and_error.txt
文件的末尾。
4. 标准输入重定向 (<
)
<
:将文件内容作为命令的标准输入。
wc -l < input.txt
会计算 input.txt
文件的行数。
5. 管道 (|
)
|
:将一个命令的标准输出作为另一个命令的标准输入。
ls -l | grep "txt"
这会列出当前目录下的所有文件,并将输出传递给 grep
命令,筛选出包含 txt
的行。
6. 重定向到 /dev/null
/dev/null
:将输出或错误重定向到/dev/null
,相当于丢弃输出。
ls /nonexistent_directory 2> /dev/null
会将错误信息丢弃,不会显示在终端上。
7. Here Document (<<
)
<<
:用于将多行输入传递给命令。
cat << EOF
This is line 1.
This is line 2.
EOF
这会将两行文本传递给 cat
命令,输出如下:
8. Here String (<<<
)
<<<
:用于将字符串作为输入传递给命令。
grep "foo" <<< "foo bar baz"
这会将字符串 foo bar baz
作为输入传递给 grep
命令,输出 foo
。
9. 重定向顺序(看不懂)
- 重定向的顺序很重要。例如:
command > file 2>&1
- 这会将标准输出和标准错误都重定向到
file
。
command 2>&1 > file
这只会将标准输出重定向到 file
,而标准错误仍然输出到终端。
10. 重定向到文件描述符(看不懂)
- 可以使用文件描述符(如
3
)来创建自定义的重定向。
exec 3> output.txt
echo "Hello, World!" >&3
exec 3>&-
这会将 Hello, World!
写入 output.txt
文件,然后关闭文件描述符 3
。
十二、文件包含
在 Shell 脚本中,文件包含(File Inclusion)是指在一个脚本中引入并执行另一个脚本的内容。可以帮助你将代码模块化,提高代码的复用性和可维护性。Shell 本身并没有像其他编程语言(如 C 或 Python)那样的专门的文件包含机制,但可以通过以下几种方式实现类似的功能。
1. 使用 source
命令
source
命令(或 .
命令)用于在当前 Shell 环境中执行指定脚本文件中的命令。这意味着被包含的脚本中的变量、函数等会在当前脚本中生效。
语法:
source filename
或
. filename
示例:
假设有一个脚本 utils.sh
,内容如下:
# utils.sh
greet() {
echo "Hello, $1!"
}
在另一个脚本 main.sh
中,你可以通过 source
命令包含 utils.sh
:
# main.sh
source utils.sh
greet "Alice"
运行 main.sh
时,输出将是:(失误,少打个 s )
2. 使用 sh
或 bash
命令
也可以使用 sh
或 bash
命令来执行另一个脚本文件。与 source
不同的是,这种方式会在子 Shell 中执行脚本,因此被包含脚本中的变量和函数不会影响当前脚本的环境。
语法:
sh filename
或
bash filename
示例:
继续使用上面的 utils.sh
和 main.sh
,但这次使用 bash
命令:
# main.sh
bash utils.sh
greet "Alice"
运行 main.sh
时,会报错,因为 greet
函数在子 Shell 中定义,不会在当前 Shell 中生效。
3. 使用 exec
命令
exec
命令可以用于替换当前 Shell 进程为指定的命令或脚本。这意味着当前脚本的执行会停止,转而执行被包含的脚本。
语法:
exec filename
示例:
# main.sh
echo "This will not be executed"
exec bash utils.sh
echo "This will not be executed either"
4. 使用 cat
和 eval
可以使用 cat
命令读取文件内容,然后通过 eval
执行这些内容。
语法:
eval "$(cat filename)"
示例:
# main.sh
eval "$(cat utils.sh)"
greet "Alice"
运行 main.sh
时,输出将是:
总结
在 Shell 脚本中,文件包含可以通过多种方式实现,最常见的是使用 source
或 .
命令。这种方式允许你在当前 Shell 环境中执行另一个脚本,使得变量、函数等可以在当前脚本中使用。