Contents

迭代ls命令输出的不同方法

1. 概述

在本教程中,我们将看到如何迭代ls -l命令的输出。默认情况下,当我们读取命令的输出时,行被单词边界分割。但是我们希望将整个行作为一个整体处理,直到我们到达一个新的行字符。我们将看到如何更改此默认行为。

2. 问题

首先,让我们看看手头的问题。考虑我们有三个文件:

$ ls -l
total 16
-rw-r--r-- 1 bluelake bluelake 3278 Feb 11 17:01 test1.txt
-rw-r--r-- 1 bluelake bluelake 3227 Feb 11 17:01 test2.txt
-rw-r--r-- 1 bluelake bluelake 7392 Feb 11 17:01 test3.txt

让我们使用一个简单的 for 循环来遍历ls -l命令的结果:

$ for line in $(ls -l); do echo $line; done
total
20
-rw-r--r--
1
bluelake
bluelake
3278
Feb
11
17:01
test1.txt
-rw-r--r--
1
bluelake
bluelake
3227
Feb
11
17:01
test2.txt
-rw-r--r--
1
bluelake
bluelake
7392
Feb
11
17:01
test3.txt

在这里,我们可以看到结果被单词边界分成不同的行。输出中的每个单词都被提取并发送到标准输出。 显然,这不是我们需要的。所以现在,让我们看看我们可以解决这个问题的不同方法。

3. 更改 IFS 变量

如上所见,按字分割的原因是因为内部字段分隔符(IFS )变量设置为默认值。并且使用默认值,它按空格分割单词。

让我们尝试将其更改为新行,看看它是如何工作的:

$ IFS='
> '
$ for line in `ls -l`; do echo $line; done
total 20
-rw-r--r-- 1 bluelake bluelake 3278 Feb 11 17:01 test1.txt
-rw-r--r-- 1 bluelake bluelake 3227 Feb 11 17:01 test2.txt
-rw-r--r-- 1 bluelake bluelake 7392 Feb 11 17:01 test3.txt

上述结果表明,它不是逐字处理,而是正确处理了一整行

但是,如果我们像这样更改IFS变量的值,它将影响将在同一会话中运行的所有命令。

为避免这种情况,我们可以在子 shell 中运行它:

$ (IFS='
> '
> for line in `ls -l`; do echo $line; done)
total 20
-rw-r--r-- 1 bluelake bluelake 3278 Feb 11 17:01 test1.txt
-rw-r--r-- 1 bluelake bluelake 3227 Feb 11 17:01 test2.txt
-rw-r--r-- 1 bluelake bluelake 7392 Feb 11 17:01 test3.txt

现在,如果我们再次运行for循环,它将打印一行中的每个单词,因为我们没有更改此会话的IFS变量。

4. 使用read命令

众所周知,我们可以使用 read 命令从标准输入中读取一行并将其拆分为单词。因此,让我们看看如何根据需要使用read命令:

$ ls -l | while read line; do echo $line; done
total 20
-rw-r--r-- 1 bluelake bluelake 3278 Feb 11 17:01 test1.txt
-rw-r--r-- 1 bluelake bluelake 3227 Feb 11 17:01 test2.txt
-rw-r--r-- 1 bluelake bluelake 7392 Feb 11 17:01 test3.txt

我们可以看到read命令将整行读入 line 变量。从那个变量中,我们能够使用 echo 命令将每一行打印到标准输出

5. 使用awk命令

awk 是处理文本和流的绝佳实用程序。让我们看看我们如何使用awk命令来完成这个特定的任务:

$ ls -l | awk '{print $0}'
total 24
-rw-r--r-- 1 bluelake bluelake 3278 Feb 11 17:01 test1.txt
-rw-r--r-- 1 bluelake bluelake 3227 Feb 11 17:01 test2.txt
-rw-r--r-- 1 bluelake bluelake 7392 Feb 11 17:01 test3.txt

从上面的结果中,我们可以看到我们已经遍历了命令输出中的所有行。在这里,我们使用了*awk命令的$0*选项来打印整个记录**。

众所周知,  awk命令让我们可以通过提及它们的索引来选择一列或多列。这样,它通过仅选择输出中需要的那些列为我们提供了更大的灵活性

6. 使用xargs命令

使用/xargs 命令,我们知道我们可以从标准输入中获取参数并将它们提供给另一个命令。让我们检查一下如何使用*/xargs*命令:

$ ls -l | xargs -I{} echo "{}"
total 24
-rw-r--r-- 1 bluelake bluelake 3278 Feb 11 17:01 test1.txt
-rw-r--r-- 1 bluelake bluelake 3227 Feb 11 17:01 test2.txt
-rw-r--r-- 1 bluelake bluelake 7392 Feb 11 17:01 test3.txt

从结果可以看出,每一行都是单独处理的。 使用-I*选项,我们一次从输出中获取一行*。然后我们可以处理那条线。在这里,我们将这条线与标准相呼应。

7. 使用parallel命令

最后,我们可以使用 GNUparallel 命令,它并行运行任务,这样一个任务就不会等待另一个任务开始。让我们看一个例子:

$ ls -l | parallel --jobs 4 echo
total 20
-rw-r--r-- 1 bluelake bluelake 3278 Feb 11 17:01 test1.txt
-rw-r--r-- 1 bluelake bluelake 3227 Feb 11 17:01 test2.txt
-rw-r--r-- 1 bluelake bluelake 7392 Feb 11 17:01 test3.txt

在这里,我们使用了 jobs选项来运行四个并行作业。**当我们必须并行处理几个大文件时,**这将派上用场。