我正在编写一个 bash 脚本,希望它告诉我目录中的文件名是否出现在文本文件中,如果没有,则删除它们。
像这样的东西:
counter = 1
numFiles = ls -1 TestDir/ | wc -l
while [$counter -lt $numFiles]
do
if [file in TestDir/ not in fileNames.txt]
then
rm file
fi
((counter++))
done
答案1
不要将文件列表保存在变量中,而是循环名称:
for name in TestDir/*; do
# the rest of the code
done
要测试是否$name
出现在 中fileNames.txt
,请使用grep -q
:
for name in TestDir/*; do
if ! grep -qxF "$name" fileNames.txt; then
echo rm "$name"
fi
done
makes执行字符串比较,而不是正则表达式匹配。使用 时,我们-F
没有得到任何输出,只有一个可以与语句一起使用的退出状态(如果找到字符串,则为 true,但感叹号会反转测试的含义)。 表示字符串需要匹配整行,从头到尾,而不仅仅是一行的一部分。grep
-q
grep
if
-x
grep
$name
rm
我已经用保护了实际echo
。运行并确保删除正确的文件。
如果列出的文件名没有TestDir
路径,则将$name
命令更改grep
为${name##*/}
:
for name in TestDir/*; do
if ! grep -qxF "${name##*/}" fileNames.txt; then
echo rm "$name"
fi
done
这将查找路径的文件名部分$name
而不是完整路径,包括TestDir
.
答案2
和zsh
:
expected=(${(f)"$(<fileNames.txt)"}) || exit
cd TestDir || exit
actual=(*(D))
superfluous=(${actual:|expected})
if (($#superfluous)) {
echo These files are not in the expected list:
printf ' - %q\n' $superfluous
read -q '?Do you want to delete them? ' && rm -rf -- $superfluous
}
答案3
这是使用您的方法的工作版本:
#!/bin/bash
fileList="$1"
targetDir="$2"
## Read the list of files into an associative array
declare -A filesInFile
while IFS= read -r file; do
filesInFile["$file"]=1
done < "$fileList"
## Collect the files in the target dir
filesInDir=("$targetDir"/*);
for file in "${filesInDir[@]}"; do
file=${file##*/}; # get the name of the file; remove path
## If this file has no entry in the array, delete
if [[ -z "${filesInFile[$file]}" ]]; then
echo "rm $file"
fi
done
删除echo
即可实际删除文件。请注意,我没有检查文件数量是否不同,因为考虑到文件数量可能相同,但您仍然可能拥有名称不在列表中的文件,这似乎没有多大意义。