当前位置:   article > 正文

Linux报错:sort: write failed: ‘standard output‘: Broken pipe;sort: write error(head -n管道接收端提前关闭致输入端报错)_sort: write failed: 'standard output': broken pipe

sort: write failed: 'standard output': broken pipe

问题

我脚本中执行find "$directory" -type f -name "*.jpg" -printf "%T@ %p\n" | sort -n | head -n $num_to_delete | awk '{print $2}' | xargs rm提示:

sort: write failed: 'standard output': Broken pipe
sort: write error
  • 1
  • 2

在这里插入图片描述

先分析下find "$directory" -type f -name "*.jpg" -printf "%T@ %p\n" | sort -n | head -n $num_to_delete | awk '{print $2}' | xargs rm命令

在这里插入图片描述

这段代码是一个shell命令,用于删除指定目录下最旧的若干个jpg文件。

解释各部分的含义如下:

  1. find "$directory" -type f -name "*.jpg":使用find命令在指定目录下查找所有的jpg文件。"$directory"是要查找的目录路径,-type f表示只查找文件-name "*.jpg"表示只查找文件名以.jpg结尾的文件。

  2. -printf "%T@ %p\n"-printf选项用于指定输出格式。%T@表示输出文件的最后修改时间(以秒为单位),%p表示输出文件的路径。\n表示输出换行。

  3. | sort -n:使用sort命令对前一步输出的结果进行排序。-n表示按照数值大小进行排序。

  4. | head -n $num_to_delete:使用head命令取前面排序结果中的前$num_to_delete行。$num_to_delete是一个变量,表示要删除的文件数量。

  5. | awk '{print $2}':使用awk命令提取前一步输出结果中的第二列(即文件路径)。{print $2}表示打印第二列。

  6. | xargs rm:使用xargs命令将前一步输出的文件路径作为参数传递给rm命令,从而删除这些文件。

报错产生原因

这个错误通常是由于管道中的某个命令提前退出导致的。在命令中,sort命令的输出被传递给head命令,然后再传递给awk命令,最后传递给xargs命令。当head命令读取到指定的行数后,它会提前退出,这可能导致sort命令无法将所有数据写入管道,从而引发"Broken pipe"错误。

疑问:为什么当head命令读取到指定的行数后,它会提前退出?

head命令是用来显示文件的开头几行,默认情况下显示前10行。当指定了-n参数后,head命令会显示指定行数的内容,并在显示完指定行数后退出。

在上述命令中,head -n $num_to_delete的作用是显示sort命令输出的前$num_to_delete行。一旦head命令显示完指定行数的内容,它就会提前退出,不再等待后续的输入。

由于sort命令的输出是通过管道传递给head命令的,当head命令提前退出时,管道中的写入端会被关闭,而sort命令可能还在尝试写入数据,这就导致了"Broken pipe"错误。

解决办法:用awk命令的NR功能替换head -n,换成find "$directory" -type f -name "*.jpg" -printf "%T@ %p\n" | sort -n | awk -v num=$num_to_delete 'NR <= num {print $2}' | xargs rm

可以使用awk命令来实现head命令的功能,awk -v num=$num_to_delete 'NR <= num {print $2}'不会像head -n命令那样提前关闭管道输出。

修改后的命令如下:

find "$directory" -type f -name "*.jpg" -printf "%T@ %p\n" | sort -n | awk -v num=$num_to_delete 'NR <= num {print $2}' | xargs rm
  • 1

解释:

当使用awk命令时,可以使用-v选项来定义一个变量。在这个命令中,我们使用-v num=$num_to_delete将Shell变量$num_to_delete传递给awk命令,并将其赋值给awk的变量num

awk命令中的NR表示当前处理的行号,$2表示当前行的第二个字段。通过NR <= num,我们限制了只处理行号小于等于num的行。然后,对于满足条件的行,我们使用{print $2}来打印第二个字段。

换句话说,这个awk命令的作用是只打印前num_to_delete行的第二个字段。在命令中,这个awk命令的输出将作为xargs命令的输入,用于删除相应的文件。

替换了后,现在没再报错了:

在这里插入图片描述

20240523 解决方法2(临时文件方法)(建议)

另一个避免管道错误的方法是使用临时文件而不是管道:

tmpfile=$(mktemp)
find "$DIRECTORY" -type f -printf '%T@ %p\n' | sort -n > "$tmpfile"
head -n "$num_files_to_delete" "$tmpfile" | cut -d' ' -f2- | xargs -d '\n' -r rm
rm "$tmpfile"
  • 1
  • 2
  • 3
  • 4

这种方法通过避免直接的管道通信来规避“Broken pipe”错误,因为数据首先被写入临时文件,然后再从文件中读取需要的部分数据。

命令解释

这个脚本的每一部分都是为了安全有效地删除目录中最旧的一定数量的文件而设计的。下面是每一部分的详细解释:

  1. 创建临时文件

    tmpfile=$(mktemp)
    
    • 1

    这行代码使用 mktemp 命令创建一个临时文件,并将其路径存储在变量 tmpfile 中。mktemp 自动生成一个唯一的文件名,通常位于系统的临时文件夹下(如 /tmp),这保证了文件名的唯一性,避免了文件名冲突。

  2. 查找和排序文件

    find "$DIRECTORY" -type f -printf '%T@ %p\n' | sort -n > "$tmpfile"
    
    • 1
    • find "$DIRECTORY" -type f -printf '%T@ %p\n':这个 find 命令搜索指定目录($DIRECTORY)下的所有文件(不包括目录),并对每个文件输出其最后修改时间(以 Unix 时间戳格式)和路径。输出格式为时间戳和路径之间有一个空格分隔。
    • sort -n:这个 sort 命令按数字顺序(-n)对输入进行排序,因为时间戳是数字,所以这会按照文件的修改时间从旧到新排序。
    • > "$tmpfile":将 sort 命令的输出重定向到临时文件中。这样做可以避免在管道中处理大量数据时可能出现的问题。
  3. 提取并删除文件

    head -n "$num_files_to_delete" "$tmpfile" | cut -d' ' -f2- | xargs -d '\n' -r rm
    
    • 1
    • head -n "$num_files_to_delete" "$tmpfile":这个 head 命令从临时文件中读取前 $num_files_to_delete 行,即最旧的那些文件的路径。
    • cut -d' ' -f2-:这个 cut 命令用于从每行中分割出文件路径。因为每行的格式是“时间戳 文件路径”,所以使用空格(-d ' ')作为分隔符,并取第二个字段到最后(-f2-),即文件路径。
    • xargs -d '\n' -r rmxargs 命令用于从标准输入接收文件路径,并执行 rm 删除这些文件。-d '\n' 指定输入项的分隔符是换行符,-r 表示如果没有输入则不执行任何操作。
  4. 删除临时文件

    rm "$tmpfile"
    
    • 1

    这行命令用于在操作完成后删除临时文件,清理脚本运行时产生的临时数据。

整个脚本的设计考虑到了效率和安全性,使用临时文件来处理可能的大量数据,同时确保在异常情况下不会误删除文件或执行未预期的命令。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/942586
推荐阅读
相关标签
  

闽ICP备14008679号