组命令和子shell
打坏 允许将命令组合在一起。 这可以通过以下两种方式之一完成; 或者 组命令 或与 子壳. 以下是每个语法的示例:
组命令:
{命令1; 命令2; [命令3; ...] }
子外壳:
(命令 1;命令 2;[命令 3;...])
这两种形式的区别在于组命令用大括号将其命令括起来,而子shell 使用括号。 需要注意的是,由于方式 打坏 实现组命令,大括号必须用空格与命令分开,最后一个命令必须在右大括号之前以分号或换行符结束。
那么组命令和子shell 有什么用呢? 虽然它们有一个重要的区别(我们稍后会谈到),但它们都用于管理重定向。 让我们考虑一个对多个命令执行重定向的脚本段:
ls -l > 输出.txt
echo "foo.txt 列表" >> output.txt cat foo.txt >> output.txt
ls -l > 输出.txt
echo "foo.txt 列表" >> output.txt cat foo.txt >> output.txt
这很简单。 三个命令的输出重定向到一个名为 输出.txt. 使用 group 命令,我们可以这样编码:
{ ls -l; echo "foo.txt 列表"; 猫 foo.txt; } > 输出.txt
{ ls -l; echo "foo.txt 列表"; 猫 foo.txt; } > 输出.txt
使用子shell是类似的:
(ls -l; echo "Listing of foo.txt"; cat foo.txt) > output.txt
(ls -l; echo "Listing of foo.txt"; cat foo.txt) > output.txt
使用这种技术我们可以节省一些输入,但是组命令或子 shell 真正闪耀的地方是管道。 在构建命令管道时,将多个命令的结果组合到单个流中通常很有用。 组命令和子 shell 使这变得容易:
{ ls -l; echo "foo.txt 列表"; 猫 foo.txt; } | 流量
{ ls -l; echo "foo.txt 列表"; 猫 foo.txt; } | 流量
在这里,我们组合了三个命令的输出并将它们通过管道传输到 LPR 生成打印报告。
在接下来的脚本中,我们将使用组命令并查看可以与关联数组结合使用的几种编程技术。 这个脚本叫做 阵列 2, 当给定目录名称时,打印目录中文件的列表以及文件所有者和组所有者的名称。 在列表的末尾,脚本会打印属于每个所有者和组的文件数。 在这里,我们看到脚本被赋予目录时的结果(为简洁起见而进行了压缩)
/usr/bin:
[我@linuxbox ~]$ 阵列 2 /usr/bin | ||
/usr/bin/2to3-2.6 | 根 | 根 |
/usr/bin/2to3 | 根 | 根 |
/usr/bin/a2p | 根 | 根 |
/usr/bin/浏览器 | 根 | 根 |
/usr/bin/连接 | 根 | 根 |
/usr/bin/acpi_fakekey | 根 | 根 |
/usr/bin/acpi_listen | 根 | 根 |
/usr/bin/add-apt-存储库 | 根 | 根 |
. | ||
. | ||
. | ||
/usr/bin/zipgrep | 根 | 根 |
/usr/bin/压缩信息 | 根 | 根 |
/usr/bin/zipnote | 根 | 根 |
/usr/bin/zip | 根 | 根 |
/usr/bin/zipsplit /usr/bin/zjsdecode /usr/bin/zsoelim | 根根根 | 根根根 | |
文件所有者:守护进程:1 | 文件(S) | ||
根:1394 | 文件(S) |
文件组所有者:crontab:1 个文件守护程序:1 个文件 lpadmin:1 个文件 mail:4 个文件 mlocate:1 个文件 root:1380 个文件 shadow:2 个文件(s) ssh : 1 个文件
tty : 2 个文件
utmp : 2 个文件
#!/斌/庆典
#!/斌/庆典
# array-2:使用数组来统计文件所有者
如果 [[ ! -d "$1" ]]; 然后
echo "用法:array-2 目录" >&2 exit 1
fi
因为我在“$1”/*; do owner=$(stat -c %U "$i") group=$(stat -c %G "$i") files["$i"]="$i" file_owner["$i"]=$ owner file_group["$i"]=$group ((++owners[$owner])) ((++groups[$group]))
完成
# 列出收集到的文件
{ for i in "${files[@]}"; 做 printf "%-40s %-10s %-10s\n" \
"$i" ${file_owner["$i"]} ${file_group["$i"]} 完成 } | 种类
# array-2:使用数组来统计文件所有者
如果 [[ ! -d "$1" ]]; 然后
echo "用法:array-2 目录" >&2 exit 1
fi
因为我在“$1”/*; do owner=$(stat -c %U "$i") group=$(stat -c %G "$i") files["$i"]="$i" file_owner["$i"]=$ owner file_group["$i"]=$group ((++owners[$owner])) ((++groups[$group]))
完成
# 列出收集到的文件
{ for i in "${files[@]}"; 做 printf "%-40s %-10s %-10s\n" \
"$i" ${file_owner["$i"]} ${file_group["$i"]} 完成 } | 种类
这是脚本的列表(带有行号):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
27
28
29
30
31
32
33
34
35
36
37
38
39
40
回音
回音
# 列出所有者
echo "文件所有者:"
{ for i in "${!owners[@]}"; 做
printf "%-10s: %5d 个文件\n" "$i" ${owners["$i"]} done } | 种类
回音
# 列出组
echo "文件组所有者:"
{ for i in "${!groups[@]}"; 做
printf "%-10s: %5d 个文件\n" "$i" ${groups["$i"]} 完成 } | 种类
# 列出所有者
echo "文件所有者:"
{ for i in "${!owners[@]}"; 做
printf "%-10s: %5d 个文件\n" "$i" ${owners["$i"]} done } | 种类
回音
# 列出组
echo "文件组所有者:"
{ for i in "${!groups[@]}"; 做
printf "%-10s: %5d 个文件\n" "$i" ${groups["$i"]} 完成 } | 种类
让我们来看看这个脚本的机制:
线5: 关联数组必须使用 宣布 使用命令 -A
选项。 在这个脚本中,我们创建了五个数组,如下所示:
files 包含目录中文件的名称,按文件名索引 file_group 包含每个文件的组所有者,按文件名索引 file_owner 包含每个文件的所有者,按文件名索引groups 包含属于索引组所有者的文件数包含属于索引所有者的文件数
第 7-10 行:检查是否将有效的目录名称作为位置参数传递。 如果不是,则会显示一条用法消息,并且脚本以退出状态 1 退出。
第 12-20 行: 循环遍历目录中的文件。 使用 统计 命令,第 13 和 14 行提取文件所有者和组所有者的名称,并使用文件名作为数组索引将值分配给它们各自的数组(第 16、17 行)。 同样,文件名本身被分配给 档 数组(第 15 行)。
第 18-19 行:属于文件所有者和组所有者的文件总数加 XNUMX。
第 22-27 行: 输出文件列表。 这是使用“${array[@]}”参数扩展完成的,该参数扩展扩展为整个数组元素列表,每个元素都被视为一个单独的词。 这允许文件名可能包含嵌入的空格。 还要注意整个循环都用大括号括起来,从而形成一个组命令。 这允许循环的整个输出通过管道传输到 分类 命令。 这是必要的,因为数组元素的扩展没有排序。
第 29-40 行:这两个循环与文件列表循环相似,只是它们使用了“${!
array[@]}" 扩展,它扩展到数组索引列表而不是数组元素列表。