Unix Bash Shell脚本编程文件大小

3

我正在编写一个 Bash shell 脚本,需要按文件大小顺序显示给定目录中的文件。如果文件大小为 0,则需要询问用户是否要删除。目前我的脚本如下:

#!/bin/bash
FILE=$(ls -S $1)
for FIL in ${FILE}
do
    echo ${FIL}
done

这会按大小顺序显示文件,但我不确定如何提示用户删除大小为0的文件。
谢谢你的帮助!

不要解析 ls 命令的输出。 - miken32
4个回答

3
find /your/path/ -size 0 -exec echo rm -i {} \; # will fail if there are spaces in any file names

更好的方式:
find /your/path/ -size 0 -print0 | xargs -0 rm -i

删除文件时,请去除回声

感谢@Will、@AdamKatz。


1
这并没有回答提示。 - Will
我想使用xargs的相同答案也可以起作用:find /your/path/ -size 0 | xargs -p -I {} rm -f {} ; - Francois
1
@Will 可以只使用 rm -i 吗? - Benjamin W.
我能否在for循环中使用FIL代替路径来使用这种方法?我尝试用FIL替换路径,但出现了“条件二进制运算符预期”的错误。 - tfreiner
由于某种原因它没有保留我的格式,抱歉。 - tfreiner
显示剩余8条评论

3

如果我们想尽可能地接近您当前的方法,我们可以这样做:

#!/bin/bash
FILE="$(ls -S "$1")"

for f in $FILE
do
    file_size_bytes=$(du "$f" | cut -f1)
    echo "$f"

    if [[ "$file_size_bytes" -eq 0 ]]
    then
        read -r -p "Would you like to delete the zero-byte file ${f}? [Y/n]: " input

        if [[ "$input" = [Yy] ]]
        then
            rm "$f"
        fi
    fi
done

另一个答案使用了`stat`,但是`stat`不是POSIX或可移植的,但如果你只在Linux下运行,`stat`是一个好的方法。
在上面的例子中,使用了`read -p`来提示用户输入,并将结果存储在`$input`中。我们使用`[[ "$input" = [Yy] ]]`来查看输入是否为`Y`或`y`。
目前的写法需要输入`y`或`Y`并按回车键才能删除文件。如果您希望它在用户按下`y`或`Y`时立即执行,请在`read`中添加`-n 1`以使其仅读取一个字符。
除非将变量放入另一个字符串中,否则也不需要使用`${var}`,或者如果需要使用某种参数扩展。
顺便说一句,这听起来像是某种作业或学习体验,因此,请查找以上所有命令、选项和语法元素,并真正学习它们的工作原理。

我在man页面中没有看到du命令的-b选项。我应该指定操作系统,我正在我的Mac上运行El Capitan。 - tfreiner
啊,在我的Yosemite Mac上有它,很奇怪。你可以把 -b去掉,它的功能仍然是一样的;“bytes”是默认行为。我在我的答案里刚刚把它去掉了。没有 -b更具可移植性。找得好! - Will
我去掉了-b选项,不再看到错误,但是当我运行脚本时,我的屏幕被整数覆盖。我删除了嵌套的if,以便先让外部if起作用。在外部if的“then”行之后,我添加了“echo zero”。我无法弄清楚这些数字来自哪里 :/ - tfreiner
如果您的文件名中有空格,使用 for f in $FILE 会发生什么?也许可以考虑设置 IFS - David C. Rankin
好的,OP解析了ls的输出;我没有。shellcheck比那个更好地警告了我 ;) 但目标是对OP的解决方案进行最小限度的更改。如果是我,我也会使用相同的命令管道获取大小和文件名,然后在IFS= while read line; ...中解析它。 - Will

2

您可以利用重定向并将stdin重定向到另一个文件描述符,同时使用进程替换来完成您的目标。例如:

#!/bin/bash

[ -z "$1" ] && {
    printf "error: insufficient input, usage: %s <path>\n" "${0//*\/}"
    exit 0;
}

exec 3<&0   # temprorary redirection of stdin to fd 3

while read -r line; do
    printf " rm '%s' ? " "$line"
    read -u 3 ans   # read answer for fd 3
    anslower="${ans,,}"
    if [ "${anslower:0:1}" = "y" ]; then
        printf " %s  =>  removed.\n" "$line"
        # rm "$line"
    else
        printf " %s  =>  unchanged.\n" "$line"
    fi
done < <(find "$1" -type f -size 0)

exec 3<&-   # close temporary redirection

注意: 实际的rm命令已被注释掉,以确保在测试完成之前不会意外删除所需文件。

示例用法/输出

$ bash findzerosz.sh ../tmp/stack/dat/tmp/tst/tdir
 rm '../tmp/stack/dat/tmp/tst/tdir/file4.html' ? n
 ../tmp/stack/dat/tmp/tst/tdir/file4.html  =>  unchanged.
 rm '../tmp/stack/dat/tmp/tst/tdir/file1.html' ? y
 ../tmp/stack/dat/tmp/tst/tdir/file1.html  =>  removed.
 rm '../tmp/stack/dat/tmp/tst/tdir/file2.html' ? y
 ../tmp/stack/dat/tmp/tst/tdir/file2.html  =>  removed.
 rm '../tmp/stack/dat/tmp/tst/tdir/file3.html' ? Y
 ../tmp/stack/dat/tmp/tst/tdir/file3.html  =>  removed.
 rm '../tmp/stack/dat/tmp/tst/tdir/file5.html' ? n
 ../tmp/stack/dat/tmp/tst/tdir/file5.html  =>  unchanged.

可以添加类似于“-printf '%s %p\n' | sort -rn”的内容来匹配排序方面的问题。 - Reinstate Monica Please

0

这个会起作用,用于测试一个文件大小是否为0(你只需要将它包含在循环中即可)。

myfilesize=`stat -c %s "$FIL"`

if [ $myfilesize = 0 ];then
echo "the file size is zero, do you want to delete it ?"
read -p "yes/no? " -n 1 -r
echo #Move to Next line
if [[ $REPLY =~ ^[Yy]$ ]]
then
    rm "$FIL"
fi
else
echo "File size is not Zero"
fi

当我尝试这个时,我在第一行得到了一个“非法选项--c”的错误,并且在第一个if语句的那一行得到了一个“一元运算符预期”的错误。当我在stat上运行man时,我没有看到-c选项显示。 - tfreiner
@tfreiner 这是什么操作系统?--printf "%s"能用吗?不过,是的,stat不太可移植,主要是Linux的东西。这就是我选择 du -b 的原因,它是符合POSIX标准的! :) - Will

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接