shell 脚本中的命令头出现输出错误

shell 脚本中的命令头出现输出错误

head 命令出错。目录中有两个大小为 48 字节的文件,其随目录路径打印一次而不是两次。为什么 head 命令不考虑前两个文件,即head -n 2?还有其他方法可以做吗?

我的代码:

find "$dir" -type f -printf '%s %p\n' | sort -n -r | head -n 2|
             {
              read -r file dir
              printf "size: %d\n\t%s\n" "$file" "$dir"
              }

我的输出错误:

size: 48
      testdir/file7.txt

testdir 目录包含两个大小相同的文件 48 但仅与目录路径一起抛出一次而不是两次

我想要的输出:

size: 48
      testdir/file7.txt
      testdir/file1.txt

答案1

head -n 2;没有错误您可以通过删除|和后续代码来检查这一点。

问题是大括号之间的代码只执行一次 - 它不是循环。并且read仅从单行输入读取数据。因此,您需要进行某种循环来打印多个文件的数据。

您可以使用while循环,也可以利用 awk 的内置循环来读取和打印数据。例如,如果当前文件的大小与前一个文件的大小不同,下面的 awk 命令仅打印大小信息。

awk 'BEGIN{size=-1}; {if($1!=size){size=$1; printf "size: %d\n", size}; printf "\t%s\n", $2}'

我们不真的需要显式初始化size,因为它会自动初始化为空字符串,但恕我直言,明确这些事情是很好的。


该 awk 命令替换了

{
    read -r file dir
    printf "size: %d\n\t%s\n" "$file" "$dir"
}

您的代码部分。换句话说,您可以使用

find "$dir" -type f -printf '%s %p\n' |
sort -n -r | head -n 2 |
awk 'BEGIN{size=-1}; 
{if($1!=size){size=$1; printf "size: %d\n", size}; 
printf "\t%s\n", $2}'

您可以将其全部放在一行中,也可以将其拆分为多行。也可以将 awk 程序放入其自己的文件中,但对于如此小的程序没有必要这样做。

请注意,您可以-n选择head任意大小,并且 awk 程序将按预期运行。另请注意 awk 是非常read快速 - 它比使用和更有效printf

FWIW,用于简单文本处理的 awk 代码通常比同等的 Python 代码快得多,因此尽管许多人认为 awk 已经过时,但它仍然相当流行。


打印数据仅有的目录中最大的文件,您可以这样做:

find . -type f -printf '%s %p\n' | 
sort -nr | 
awk 'NR==1{size=$1;printf "size: %d\n", size};
$1!=size{exit};
{printf "\t%s\n", $2}'

表示仅当记录数等于 1 时才NR==1执行以下块( 中的内容) - 一条记录只是一行。{}因此,我们获取第一个文件的大小,这是最大的文件(感谢前面的sort命令),将其保存在size变量中,然后打印大小。

$1!=size{exit}表示一旦我们读到第一个字段中的数据与我们保存在变量中的数据不匹配的行,就退出程序size

最后一个块 {printf "\t%s\n", $2}打印每个文件的路径名。


有多种方法可以打印该find命令找到的最大和最小文件。一种方法是将所有数据读入 awk,将其存储在数组中,对数组进行排序,然后打印最大和最小大小的文件的数据。但我将在这里采用更简单的策略,并回收我现有的代码。为了更有效地完成此操作,我将 awk 程序放入一个文件中。将此文件保存到命令路径中的目录并授予其执行权限。

field1match.awk

#!/usr/bin/awk -f

# print only the records whose 1st field matches that of the 1st record
# Written by PM 2Ring 2015.05.21

NR==1{size=$1; printf "size: %d\n", size}
$1!=size{exit}
{printf "\t%s\n", $2}

这是命令行,用于tee复制输出find,然后对其进行排序并使用进程替换进行打印:

find "$dir" -type f -printf '%s %p\n' | 
tee > >(sort -n | field1match.awk) >(sort -rn | field1match.awk)

相关内容