传递命令的输出作为另一个参数
1. 概述
在使用 Linux 命令行时,我们使用许多接收重要数据作为参数的命令。 在本教程中,我们将探讨一些关于如何将程序的输出用作其他人的参数的场景。
2. 准备示例文件
首先,让我们创建一个可以测试我们的策略的环境。 让我们创建两个文件夹 - 一个包含使用特定规范创建的文件,另一个将用作我们测试的目标:
$ mkdir dir_example target
接下来,让我们分别创建两组大小为 10 字节和 4 字节的文件:
$ truncate -s 10 dir_example/file{1..3}.this
$ truncate -s 4 dir_example/file{1..2}.not
在这里,我们使用truncate 命令创建了两组文件,具有特定的大小,用空字符填充。
我们在文件中添加了*.this或.not*形式的后缀,以便在我们的示例中通过它们的大小在视觉上区分它们。 注意:在我们完成每个示例之后,我们必须清空目标文件夹:
$ rm target/*
3. read Builtin
一些 shell,如 Bash 和 Zsh,具有**read 内置函数,可以从输入中读取内容并将其存储在 variable**中。
让我们将大小大于 5 个字节的文件从dir_example文件夹复制到目标文件夹:
$ find dir_example/ -type f -size +5c | while read file; do cp "$file" target/; done
在这里,我们使用 带有 -type f参数的find 命令 来搜索常规文件。-size +5c参数用于仅查找大小大于 5 个字节的文件。
接下来,我们使用find命令的输出来提供while循环。read内置然后从输入中读取并将第一个单词分配给file变量。
最后,在cp 命令中使用file变量作为参数,我们可以将同名文件复制到目标文件夹中:
$ ls -l target/
total 0
-rwxrwxrwx 1 cuau cuau 10 Nov 19 11:37 file1.this
-rwxrwxrwx 1 cuau cuau 10 Nov 19 11:37 file2.this
-rwxrwxrwx 1 cuau cuau 10 Nov 19 11:37 file3.this
4. 命令替换
一些 shell 有一种称为**命令替换 的机制,它允许命令的输出替换命令名称**。 让我们使用此功能将大于 5 个字节的文件复制到target文件夹:
$ cp $(find dir_example/ -type f -size +5c) target/
在这种情况下,我们使用命令替换来提供源文件列表作为cp命令的参数。然后,我们将它们复制到最后一个参数中指示的目标文件夹。
5. 流程替代
与我们的上一个场景类似,几个 shell 有另一种称为**进程替换 的机制,它将列表的输入或输出连接到 FIFO**。然后,命令使用此 FIFO 的名称。
由于awk 只接受文件名作为参数而不是简单的单词,让我们在awk脚本中使用此功能来计算两组文件的大小:
$ awk '{hist[ARGIND]++}
END {
for (i in hist)
printf "%s records in process substitution %s\n", hist[i] , i
}' \
<(find dir_example/ -type f -size +5c) \
<(find dir_example/ -type f -size -5c)
在这里,我们分别列出了两个 FIFO 中大于和小于 5 个字节的文件。 然后,在awk脚本中,我们格式化输出以显示文件数:
3 records in process substitution 1
2 records in process substitution 2
6. xargs命令
**/xargs 是一个强大的工具,它使用标准输入构建和执行命令行。**让我们创建另一个示例文件,看看我们可以用这个命令得到什么:
$ cat - << __EOF > dir_example/file4.this.xargs
This file example
will be check by
the following line:
"choose me"
__EOF
现在,让我们尝试使用find命令输入xargs :
$ find dir_example/ -type f -size +5c \
| xargs -I {} bash -c 'grep -q "choose me" {} && cp {} target'
在这里,我们使用*-I replace-string参数将出现的替换字符串替换为*从输入中读取的名称。
接下来,我们使用bash 命令创建一个命令字符串,该命令字符串由grep 命令过滤包含字符串“choose me”的文件组成。
最后,只有在grep退出状态成功的情况下, cp才会将文件复制到目标文件夹。
这样,我们使用xargs将find的输出作为grep和cp命令的参数传递。
我们的target目录现在只包含一个文件:
$ ls -l target/
total 0
-rwxrwxrwx 1 cuau cuau 67 Nov 19 12:40 file4.this.xargs
7. GNUparallel工具
**GNUparallel 是用于并行执行作业的命令行工具。作业可以是单个命令或为输入的每一行运行的脚本。**换句话说,它就像xargs。
如果我们使用的是基于 Debian 的发行版,我们可以使用apt 命令来安装它:
$ sudo apt install -y parallel
否则,如果我们使用另一个发行版(或者如果我们想编译特定版本),我们可以手动下载并安装它:
$ mkdir -p /tmp/parallel_install \
&& curl http://ftp.gnu.org/gnu/parallel/parallel-latest.tar.bz2 \
| tar xj -C /tmp/parallel_install --strip-components 1 \
&& sudo bash -c '
cd /tmp/parallel_install \
&& ./configure \
&& make \
&& make install'
这个单行程序会将 GNU Parallel 下载到*/tmp/parallel_install*目录中。 让我们测试一下安装:
$ parallel echo ::: hello
hello
现在我们可以使用这个新工具运行一些过去的示例。 让我们将parallel与进程和命令替换相结合,将文件复制到目标文件夹中:
$ parallel cp {1} {2} :::: <(find dir_example/ -type f -size +5c) \
::: $(echo target)
在这种情况下,parallel提供的进程和命令替换的输出被用作cp命令的参数。
我们使用标记“::::”和“:::”,因为parallel使用右侧的内容分别作为文件参数和参数。
此外,我们使用字符串*{n}(其中n是一个数字)作为位置替换字符串,它将替换第n个输入源或参数,类似于xargs中的{}* 替换字符串。
让我们看看文件夹的内容:
$ ls -l target/
total 0
-rwxrwxrwx 1 cuau cuau 10 Nov 19 21:21 file1.this
-rwxrwxrwx 1 cuau cuau 10 Nov 19 21:21 file2.this
-rwxrwxrwx 1 cuau cuau 10 Nov 19 21:21 file3.this
-rwxrwxrwx 1 cuau cuau 67 Nov 19 21:21 file4.this.xargs
现在,让我们尝试xargs场景,但这次使用parallel代替xargs:
$ parallel 'grep -q "choose me" {1} && cp {1} {2}' \
:::: <(find dir_example/ -type f -size +5c) \
::: target
通过用引号括起来,我们可以运行一个组合命令。
正如预期的那样,这将复制file4.this.xargs文件:
$ head -v target/*
==> target/file4.this.xargs <==
This file example
will be check by
the following line:
"choose me"