我的情况是,我有一个充满文件的古老目录,其中同样古老(写得不好)的应用程序创建文件。多年来,已经创建了数百个带有前导,尾随或嵌入空格或其他“特殊”字符的文件。我想清理这个烂摊子。
我可以生成一个活跃使用的文件列表。我可以将活动文件与现有文件的完整列表进行比较,并生成非活动文件的列表。我现在想要删除非活动文件。我的问题是循环遍历文件列表似乎忽略了IFR
设置。
ACTIVE=`/bin/mktemp -t`
NON_ACTIVE=`/bin/mktemp -t`
...generate active file list... > $ACTIVE
/bin/ls -1 /path/to/all/files | \
/bin/grep -Fxvf $ACTIVE > $NON_ACTIVE
我现在要删除$NON_ACTIVE
中列出的文件。我试过设置
IFR=$(/bin/echo -en '\n\b')
之前使用
/bin/rm `/bin/cat $NON_ACTIVE`
或for
循环遍历列表并删除每个文件。我还没有找到让我打败名字不好的文件的魔力。想法?
我想我可以编辑$NON_ACTIVE
并将rm
添加到每一行,并将每个凌乱的文件名用单引号括起来,但我想编写整个过程的脚本 - 并学习(或重新学习)在路上的东西。
答案 0 :(得分:0)
这是一种适用于所有可能的文件名的方法,包括当名称多于单个命令行时的名称时:
#!/bin/bash
# ^-- needed because this uses bash-only features (particularly, bash 4.0 or newer)
# build an associative array with names of active files as keys
declare -A active_files-( )
while IFS= read -r -d '' filename; do
active_files[$filename]=1
done < <(program_that_lists_active_files_with_NUL_delimiters)
# build a regular array of inactive files
inactive_files=( )
for file in *; do
[[ ${active_files[$file]} ]] || inactive_files+=( "$file" )
done
# if you want to do only one rm call, and work with lists too long to fit on a single
# rm command line...
xargs -0 -- rm -f -- < <(printf '%s\0' "${inactive_files[@]}")
如果您不关心使用非常长的非活动文件列表,最后一行可以替换为这个较短的替代方案:
rm -f -- "${inactive_files[@]}"