根据这个问题和答案: 删除文件但排除列表中的所有文件
这段代码完全满足我的需要,除了它不适用于子目录。
for i in *; do
if ! grep -qxFe "$i" filelist.txt; then
echo "Deleting: $i"
# the next line is commented out. Test it. Then uncomment to removed the files
# rm "$i"
fi
done
它似乎只是匹配文本文件中的文本,而不是将每个新行视为路径。因此,当文本文件包含以下内容时:
./leaveme.jpg
./i am staying.gif
./james/leaveme.gif
./james/
它还会尝试删除 james 目录吗?它还会忽略 james 目录中任何其他应删除的文件。
有什么方法可以让它识别文本文件中的完整路径吗?我有数千个子目录,因此在每个单独的目录上运行此脚本将需要很长时间。
答案1
尝试rsync
利用其排除选项的帮助,如下所示:
rsync --dry-run -v -r --remove-source-files \
--exclude-from='/path/to/excludefile.txt' /path/to/source/ /path/to/somewhere/to_delete
笔记:
- 该命令正在
--dry-run
模式下运行;将其移除以采取实际操作。 - 运行之前,请确保您的
excludefile.txt
位于/path/to/source
路径之外,或者将其自身添加到excludefile.txt
文件中以排除删除。 如果操作完成后有空目录,rsync 无法删除,因此你需要手动删除它们,请尝试
find /path/to/source -type d -empty -ok rmdir {} \;
如果您不想确认删除每个目录,请将命令更改为以下命令。
find /path/to/source -type d -empty -delete
参见此处演示运行添加
最后一步,仔细检查移动到的文件和目录
/path/to/somewhere/to_delete
,如果对结果满意,则删除整个目录。\rm -rfi /path/to/somewhere/to_delete # -i switch is used for confirmation, remove it if you don't needed
答案2
您可以使用find . -type f
以递归方式列出所有文件及其完整路径。-type f
省略所有目录并仅列出文件。但这里filelist.txt
应该包含我们需要从删除中排除的文件的完整路径。
IFS=$'\n'
for i in $(find . -type f); do
if ! grep -qxFe "$i" filelist.txt; then
echo "Deleting: $i"
# the next line is commented out. Test it. Then uncomment to remove the files
# rm "$i"
fi
done
答案3
假设你的exclude.txt
样子是这样的:
leaveme.jpg
i am staying.gif
james/leaveme.gif
所有子目录和文件都位于一个父目录并且您的exclude.txt
以及delete.sh
位于该父目录之外。
下面的脚本将执行以下操作:
exclude.txt
逐行读取文件名。- 查找父目录下所有匹配的文件名,并通过添加
.KEEP
后缀来标记。 - 找到父目录下所有没有标明后缀的文件
.KEEP
并删除。 - 找到父目录下的所有空子目录并删除。
.KEEP
从保存的文件中删除后缀并将其恢复为原始名称。
!!! 警告:这不是一次演习 !!!
运行时,脚本将执行上述所有操作立即地。请勿在您的实际目录上运行它,除非您先测试它以查看结果是否符合您的要求。
要首先测试脚本,请在结构和命名与所需目录相似的假复制目录上运行它。
您还可以通过更改此行来查看在实际删除文件之前将首先删除哪些文件:
find "$path" -type f ! -name "*.KEEP" -exec rm {} \;
用这一行:
find "$path" -type f ! -name "*.KEEP" -exec echo {} "Will be deleted!" \;
步入2下面只打印要删除的文件的名称而不是实际删除它们。
要创建和使用脚本,请按照以下步骤操作:
在您的主目录中创建并编辑一个脚本文件,并
delete.sh
通过在终端中运行以下命令来命名它:nano ~/delete.sh
将以下代码复制并粘贴到编辑器中,
/path/to/parent/directory/
用包含要删除的文件的目录的完整路径替换,并替换/path/to/exclude.txt
为您的完整路径exclude.txt
:
#!/bin/bash
path="/path/to/parent/directory/"
filelist="/path/to/exclude.txt"
while IFS=$'\n' read filename
do
mv -n "$path$filename" "$path$filename.KEEP"
done < "$filelist"
find "$path" -type f ! -name "*.KEEP" -exec rm {} \;
find "$path" -type d -empty -delete
while IFS=$'\n' read filename
do
mv -n "$path$filename.KEEP" "$path$filename"
done < "$filelist"
保存脚本文件并按Ctrl+X然后按退出编辑器Y。
通过在终端中运行以下命令使脚本文件可执行:
chmod +x ~/delete.sh
通过在终端中运行以下命令来运行脚本:
bash ~/delete.sh
完成后,只有列出的文件exclude.txt
留在您的父目录下。