我正在寻找一个 unix 命令序列,它能够执行相当复杂的条件删除操作。
如果文件中不存在名为“[NAME].rec”或“[NAME].mpg”的相应文件,则所有扩展名为“[NAME].cut”和“[NAME].cut.bak”的文件都将被删除。同一个文件夹。
该命令应在具有最小内核的集成设备上运行,因此不使用“特殊工具”。例如,可以使用“ls”和“rm”,不存在“find”(即仅通过外部工具,我不想依赖该工具)
如果可能,该命令也应在子目录中递归删除......
背景如下:我正在为基于Linux的PVR开发一个工具,它允许剪切录制的节目。对于每个录音(扩展名 .rec 或 .mpg),片段标记存储在 .cut 文件中。当某些录音被移动/重命名/删除时,相应的剪切文件仍保留在磁盘上无用。我已经在 C 中实现了删除那些无用的剪切文件。但我想知道是否有一个(简单的)基于系统的解决方案。在这种情况下,它可以通过“系统”和在后台运行,这将使我的应用程序响应更快......
以下是包含在 PVR 固件中的命令:
亲和力、arp、awk、基本名称、bash、busybox、cat、chgrp、chmod、chown、cmp、cp、cramfsck、剪切、日期、dd、df、dirname、dmesg、du、echo、egrep、env、expr、false、 fgrep、flash_erase、flash_eraseall、flash_info、免费、getty、grep、头、hexdump、主机名、id、ifconfig、安装、kill、killall、ln、记录器、登录、ls、md5sum、mkcramfs、mkdir、mknod、mktemp、更多、安装、mv、nice、norcleanmark、od、passwd、pidof、ping、pmtest、portmap、printenv、printf、ps、pwd、readlink、renice、rm、rmdir、路由、sed、seq、sh、关机、睡眠、排序、字符串、stty、sync、tail、tee、telnet、tftp、时间、tinylogin、touch、tr、true、tty、twin、umount、uname、uniq、usleep、vi、wc、which、whoami、xargs、yes
你有什么建议给我吗?
答案1
我不能再简单了;这有效但是它假设目标目录中不存在文件名包含换行符的文件;首先使用以下命令测试命令:
find . -type f \( -name "*.cut" -o -name "*.cut.bak" \) -exec bash -c '[ -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").rec" -o -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").mpg" ] && echo "{}"' \;
如果列出的文件是预期要删除的文件,您可以继续运行以下命令:
find . -type f \( -name "*.cut" -o -name "*.cut.bak" \) -exec bash -c '[ -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").rec" -o -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").mpg" ] && rm "{}"' \;
对临时创建的目录层次结构进行测试:
~/tmp$ tree
.
└── dir1
├── file1.cut
├── file1.cut.bak
├── file1.rec
├── file2.cut
├── file2.cut.bak
├── file2.mpg
├── file3.cut
├── file3.cut.bak
└── subdir1
├── file1.cut
├── file1.cut.bak
├── file1.rec
├── file2.cut
├── file2.cut.bak
├── file2.mpg
├── file3.cut
└── file3.cut.bak
2 directories, 16 files
~/tmp$ find . -type f \( -name "*.cut" -o -name "*.cut.bak" \) -exec bash -c 'if [ -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").rec" -o -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").mpg" ]; then rm "{}"; fi' \;
~/tmp$ tree
.
└── dir1
├── file1.rec
├── file2.mpg
├── file3.cut
├── file3.cut.bak
└── subdir1
├── file1.rec
├── file2.mpg
├── file3.cut
└── file3.cut.bak
2 directories, 8 files
如您所见,所有具有扩展名的文件.cut
或.bak
具有相同名称和扩展名的文件.rec
或.mpg
存在的文件都会被递归删除(file1.cut
和file1.cut.bak
因 而被删除file1.rec
,file2.cut
和file2.cut.bak
因 而被删除file2.mpg
;file3.cut
并且不会被删除,因为同一目录中file3.cut.bak
没有file3.rec
或file3.mpg
)
答案2
如果命令要在一些命令和 shell 非常有限的小型嵌入式设备上运行(例如,缺少find
、最小 shell à la sash
),一种可能的方法是编写一些小型 C(或者可能是 C++)程序来执行此操作,然后编译它程序到可执行文件(最好将该程序制作为免费软件)。
你会使用网络电视递归遍历文件树,并构建要删除的路径的数组(或向量或列表)。然后第二遍将有效地删除文件。相关函数有网络电视(3)(遍历文件树),snprintf(3)(构造文件名),访问(2)(测试文件是否存在),统计数据(3)(获取有关文件的类型、大小和其他元数据),删除(3)(删除文件),基本名称(3), ETC。
如果您有 GNU find
,您可以用它制作一个 shell 脚本(但详细信息可能取决于您的实际 shell,特别是如果它足够小而不符合 POSIX)。将要删除的文件名收集到某个临时文件中。然后稍后将其删除。
如果您坚持使用 shell 解决方案,并假设 GNU find 可用,您可能有几个 shell 脚本:
首先,一个 shell 脚本(从外部调用),我们将其命名为将创建一个临时文件,然后为每个&文件clean-the-mess.sh
调用另一个内部 shell 脚本 :consider-cleaning.sh
.cut
.cut.bak
#!/bin/sh
## untested clean-the-mess.sh script
## a temporary file listing files to remove
cleanlistfile=$(tempfile -s .cleanlist)
## on exit, or SIGQUIT, SIGTERM, or SIGINT signal, remove it
trap "rm $cleanlistfile" EXIT QUIT TERM INT
## find every file name .cut | .cut.bak; run consider-cleaning.sh on it
find -type f \( -name '*.cut' -o 'name '*.cut.bak' \) \
-exec consider-cleaning.sh '{}' $cleanlistfile \;
## remove the collected file list
for f in $(cat $cleanlistfile) ; do rm $f ; done
如果某些文件的名称中包含空格,则该方法将不起作用。或许可以考虑xargs(1)
然后,您需要编写内部consider-cleaning.sh
脚本,该脚本将文件路径添加到要清理的文件列表中。它可能是
#!/bin/sh
# internal untested consider-cleaning.sh script
file=$1
collectlist=$2
case $file in
*.cut)
bas=$(basename $file .cut)
if [ ! -f "$bas.rec" -a ! -f "$bas.mpg" ]; then
echo $file >> $collectlist
fi
;;
*.cur.bak)
bas=$(basename $file .cut.bak)
if [ ! -f "$bas.rec" -a ! -f "$bas.mpg" ]; then
echo $file >> $collectlist
fi
;;
esac
我的脚本未经证实、未经测试,因此可能是错误的。将#!/bin/sh -vx
其作为第一行来测试和调试它们(您将获得一些执行跟踪)
或者,嵌入一个小卢阿解释器进行一些基本的原始文件相关操作,并用 Lua 编写脚本。 Lua 非常容易嵌入,并且可以成为一个小型解释器。