删除没有数据且只有标题的文件

删除没有数据且只有标题的文件

我想删除只有标题而没有数据的文件。我尝试了下面的命令,它工作正常,唯一的问题是它给出的退出状态为 1,应该为零。

wc -l /Path/File_*  | while read CNT FN; do [ $CNT -lt 2 ] && [  "$FN" != total ] && rm "$FN"; done

我正在 Datastage ETL 工具上运行此命令,但我的工作失败了。

有没有办法修改命令以获取退出状态为0

答案1

为了避免必须读取整个文件(就像wc这样做),当您知道第一行之后文件至少有 2 行时,我会这样做(在 GNU 系统上):

LC_ALL=C gawk -v ORS='\0' '
  FNR == 2 {nextfile}
  ENDFILE  {if (FNR < 2) print FILENAME}' /path/File_* |
  xargs -r0 rm -f

这也更有效,因为它最大限度地减少了正在运行的命令数量。

更可靠,因为它适用于任意文件名。

与基于 - 的解决方案的功能差异在于wc:它不会删除包含一个分隔行后跟一个非分隔行的文件。

如果文件无法删除(并且一开始就存在),则该文件仅返回非零退出状态。


您的问题是该管道的退出状态是其中最右侧命令的退出状态(只要您不使用该pipefail选项)。

这里最右边的命令是while循环。循环的退出状态是循环中最后运行的命令的退出状态身体循环的。在您的情况下,它将是[ "$FN" != total ]在输入的最后一行运行的命令,该命令将非零,除非只有一个/path/File_*文件(在这种情况下wc不打印总数)。

如果你把它改成:

[ "$CNT" -gt 1 ] || [ "$FN" = total ] || rm -f -- "$FN"

如果最后一次,您只会获得非零退出状态标头无法删除文件。

答案2

您的条件false在循环结束时返回:

# false           # false              = false
[ $CNT -lt 2 ] && [  "$FN" != total ]

例如,如果wc -l /path返回

2 total

然后你运行命令

                                 # true           # true              = true
wc -l *  | while read CNT FN; do [ $CNT = 2 ] && [  "$FN" = total ] && echo $CNT "$FN"; done
echo $?
0

但如果你跑

                                 # false           # true              = false
wc -l *  | while read CNT FN; do [ $CNT = 3 ] && [  "$FN" = total ] && echo $CNT "$FN"; done
echo $?  
1

换句话说:

#false         # false      = false
[ 2 -eq 3 ] && [ bar = foo ]
echo $?
1

#true         # false      = false
[ 3 -eq 3 ] && [ bar = foo ]
echo $?
1

# false         # true      = false
[ 2 -eq 3 ] && [ foo = foo ]
echo $?
1

# true         # true      = true
[ 3 -eq 3 ] && [ foo = foo ]
echo $?
0

我会使用 for 循环而不是 while 循环,并使用一个函数在未找到匹配项时返回一个值:

foo() {
  ret=1 # no matches found
  for file in *.txt; do # your extension
    [[ $(wc -l "$file" | cut -d' ' -f1) -eq 1 ]] && echo "rm $file" && ret=0
  done
  return $ret
}

相关内容