Bash 脚本一般问题

Bash 脚本一般问题

我正在处理的第一部分只是创建一个名为 command_manuals 的文件夹,其中包含 bash shell 上可用的所有命令的文本文件副本,文件名是命令名称本身。除了一些不影响的异常错误消息之外脚本实现其目标,这部分我已经设法得到,但我更愿意首先讨论最严重的问题,所以我现在将其保留。

那些没有可用手册的人仍然有空文本文件,这给我带来了第二部分的目标,即删除这些“0大小文本文件”并编译一个我想在稍后部分使用的单个列表,该列表检查每次我执行 apt-update 时,“undocumented man 7”和其他部分都会使用众所周知的模式搜索包之一来查看是否添加了关于那些缺少手册的命令的新内容,ra,ra,ra 无论如何并不重要,直到我克服第二部分的戏剧性问题,到目前为止,我已经成功地将 if 条件写入 for 循环,该循环仅打印出大小为零的文件夹内容的子集,但是当我尝试重播此基本回显时,麻烦就开始了“then”和“fi”之间的命令删除空文件。

但这也给我带来了一个额外的问题,涉及我注意到的另一件奇怪的事情,即按我想要的方式工作的基本模板脚本缺少标准的 #!/bin/bash ,它始终需要作为我的 .sh 脚本的第一行以前的经验,为什么?

template_for_if_delete.sh

TOTALnum=$(wc -l < filesizes.txt);
for i in `seq 1 $TOTALnum`;
do
size=$(sed -n ''$i','$i'p' filesizes.txt)
if [ $size -eq 0 ];
then
echo $(sed -n ''$i','$i'p' filenames.txt);
fi
done;

到目前为止对于实际的我的第二个任务的脚本:

第二部分.sh

#!/bin/bash
cd;
cd command_manuals;
rm filenames.txt;
ls -1 > filenames.txt;
TOTALnum=$(wc -l < filenames.txt);
for i in `seq 1 $TOTALnum`;
do filename=echo $(sed -n ''$i','$i'p' filenames.txt);
size=$(stat -c '%s' $filename);
if [ $size -eq 0 ];
then
rm $(locate $(sed -n ''$i','$i'p' filenames.txt));
fi
done;

它产生输出(根据上面 for 循环中定义的数量重复多次):

Try 'stat --help' for more information.
./secondpart.sh: line 9: [: -eq: unary operator expected
./secondpart.sh: line 8: x86_64-linux-gnu-gold.txt: command not found
stat: missing operand

然后我尝试将 if 语句中的变量“size”更改为复杂参数扩展:

#!/bin/bash
cd;
cd command_manuals;
rm filenames.txt;
ls -1 > filenames.txt;
TOTALnum=$(wc -l < filenames.txt);
for i in `seq 1 $TOTALnum`;
do filename=echo $(sed -n ''$i','$i'p' filenames.txt);
size=$(stat -c '%s' $filename);
if [ ${#size} -eq 0 ];
then
rm $(locate $(sed -n ''$i','$i'p' filenames.txt));
fi
done;

它产生了相关的输出,询问我是否要删除一些随机的不相关的东西,此时我决定好吧,我最好在弄乱我的虚拟机之前发布一个问题,该虚拟机对我来说运行得很好:

./secondpart.sh: line 8: filenames.txt: command not found
stat: missing operand
Try 'stat --help' for more information.
rm: missing operand
Try 'rm --help' for more information.
./secondpart.sh: line 8: file-roller.txt: command not found
stat: missing operand
Try 'stat --help' for more information.
rm: missing operand
Try 'rm --help' for more information./code>
./secondpart.sh: line 8: filesizes.txt: command not found
stat: missing operand
Try 'stat --help' for more information.
rm: missing operand
Try 'rm --help' for more information.
./secondpart.sh: line 8: file.txt: command not found
stat: missing operand
Try 'stat --help' for more information.
rm: cannot remove adammvirtual/Win10UbuntuVM001_apt_sources_file.txt':
 No such file or directory
rm: cannot remove '/home/adamvirtual/mapfile.txt': No such file or directory
rm: remove write-protected regular file '/usr/share/doc/alsa-base/driver/Procfile.txt.gz'?

我按ctrl+C 来逃避提示。

答案1

问题在于./secondpart.sh: line 8,应该设置哪个$filename

stat并且rm$filename争论,所以他们在抱怨。这些错误是后续错误。

所以你需要修复第8行。

您几乎应该始终set -euo pipefail在脚本的开头让它们在出现第一个错误时退出,从而防止出现后续错误。


但总的来说,您的脚本过于复杂,使用wc循环forsed这不是正确的方法逐行读取文件

而不是使用stat -c %s来确定文件大小是否为零,您可能想要使用文件测试操作符 -s,它正是这样做的(实际上检查相反的情况,如果文件大小是不是零)。

使用例如:

xargs -a filenames.txt -I{} sh -c '[ -s "$1" ] || rm -i "$1"' xargs-sh {}

或者

readarray filenames < filenames.txt
for filename in "${filenames[@]}"; do
    [ -s "$filename" ] || rm -i "$filename"
done

或者

while IFS= read -r filename; do
    [ -s "$filename" ] || rm -i "$filename"
done < filenames.txt

一般来说,在文本文件中逐行显示文件名并不是一个好主意,因为文件名中允许包含换行符。相反,您应该始终使用空字符 ( \0) 作为文件分隔符。

相关内容