![脚本用于保留包含 .txt 文件的特定目录并从其他目录中删除不包含特定 .txt 文件的文件](https://linux22.com/image/1306067/%E8%84%9A%E6%9C%AC%E7%94%A8%E4%BA%8E%E4%BF%9D%E7%95%99%E5%8C%85%E5%90%AB%20.txt%20%E6%96%87%E4%BB%B6%E7%9A%84%E7%89%B9%E5%AE%9A%E7%9B%AE%E5%BD%95%E5%B9%B6%E4%BB%8E%E5%85%B6%E4%BB%96%E7%9B%AE%E5%BD%95%E4%B8%AD%E5%88%A0%E9%99%A4%E4%B8%8D%E5%8C%85%E5%90%AB%E7%89%B9%E5%AE%9A%20.txt%20%E6%96%87%E4%BB%B6%E7%9A%84%E6%96%87%E4%BB%B6.png)
我几乎完成了脚本,但它输出的是目录。我想要的是文件输出。你们中有人愿意帮我吗?:)
#!bin/bash
( find /testftp/* -type d ;
find /testftp/* -type f -iname DONOTDELETE.TXT -printf '%h'
) | sort | uniq -u
输出为:
/testftp/logs
输出是不存在 DONOTDELETE.TXT 的目录。非常接近。只需显示文件即可。
答案1
以下是我的看法:
#! /bin/bash
SPECIAL_FILE=DONOTDELETE
LOGFILE=clean.$(date +"%Y-%d-%m.%H%M%S").log
FIND_BASE="$1"
if [ $# -ne 1 ]; then
echo "Syntax $(basename $0) <FIND_BASE>"
exit 1
fi
if [ "$FIND_BASE" = "." ]; then
FIND_BASE=$(pwd)
else
FIND_BASE=$(pwd)/$FIND_BASE
fi
for d in $(find $FIND_BASE -type d -print); do
if [ "$d" != "$FIND_BASE" ]; then
ls $d | grep $SPECIAL_FILE &> /dev/null
if [ $? -ne 0 ]; then
echo "Deleting $d" | tee -a $LOGFILE
rm -rf $d 2>/dev/null
else
echo "Ignoring $d, contains $SPECIAL_FILE" | tee -a $LOGFILE
fi
fi
done
exit 0
将其添加到脚本中,如果愿意,使用您自己的命名约定修改变量(对于特殊文件和日志名称),然后只需使用起始目录路径作为参数调用它即可。它将排除任何包含您想要的文件的目录,并删除所有其余目录。
答案2
我想我应该尝试一下这个。
#!/bin/bash
# file name and path can not have spaces for this to work.
ignorefile=DONOTDELETE.TXT
dir="`find /testftp/* -type d`";
exists=$(ls $dir | for each in $(find $dir -type f -iname $ignorefile -printf '%h\n'); do echo -en "grep -v $each |" ; done | sed '$s/.$//')
direxists=$(ls $dir | eval $exists | grep -v $ignorefile | sed 's/:/\//g' | sort | uniq -u)
for pth in $direxists;
do
if [ -d $pth ]; then
if [ "$(ls -A $pth)" ]; then
echo rm -f ""$pth*""
fi
fi
done
复制: 更改了 dir="`find /testftp/* -type d`"; 到 dir="`find ./testftp/* -type d`"; mkdir testftp && cd testftp 对于 1 2 3 4 5 6 7 8 9 中的 x;执行 mkdir $x;完成 对于 1 2 3 4 6 7 9 中的 y;触摸 $y/blah;完成 触摸 5/DONOTDELETE.TXT 触摸 5/some.log 触摸 8/DONOTDELETE.TXT 触摸 8/另一个.文件 光盘 .. $ ./script.sh rm -f ./testftp/1/blah rm -f ./testftp/2/blah rm -f ./testftp/3/blah rm -f ./testftp/4/blah rm -f ./testftp/6/blah rm -f ./testftp/7/blah rm -f ./testftp/9/blah
答案3
如果你有 bash 4+ (使用 检查bash --version
),你可以用两行代码执行此操作:
shopt -s globstar
for f in ./**/; do [[ -f "$f"/DONOTDELETE.TXT ]] || rm -f "$f"/*; done
请注意,它shopt -s globstar
需要占一行 - 不要仅仅用 将它添加到 for 循环前面;
。
./**/
递归扩展到当前目录中的每个子目录及其子目录。如果您只想在树中向下移动一层,请使用代替./*/
(并且不必费心设置 globstar);如果您想要更精细的控制,则必须使用代替find
(特别是-maxdepth
和-mindepth
选项)。如果您的任何目录以 : 开头,我会使用./**/
代替,这样可以防止它们被视为**/
-
[[ -f "$f"/DONOTDELETE.TXT ]]
测试该文件是否存在并且是否是文件(如果您希望它即使 DONOTDELETE.TXT 可能不是文件也能正常工作,请使用-e
而不是-f
)。严格来说,您不需要在/
那里,因为 $f 包含尾部斜杠,但我认为这样看起来更好,而且通常多余的正斜杠是无害的。||
表示或 - 当(且仅当)该测试评估为错误的,那么它右边的代码将被执行,在本例中rm -f "$f"/*
,它将删除除隐藏文件之外的所有文件。
如果您还想删除隐藏文件,可以使用以下命令:
for f in ./**/; do [[ -f "$f"/DONOTDELETE.TXT ]] || rm -f "$f"/* "$f"/.*; done