如何删除目录中除少数几个文件之外的所有文件?

时间:2017-06-14 20:35:14

标签: linux bash unix

我想通过shell脚本删除目录中的所有文件。文件名将作为命令行参数传递,参数数量可能不同。

假设目录包含以下5个文件:

 1.txt, 2.txt, 3.txt. 4.txt. 5.txt

我想通过使用文件名的shell脚本从中删除两个文件。此外,文件数可能会有所不同。

4 个答案:

答案 0 :(得分:1)

可以通过以下几种方式完成,但是对于大型目录而言,最强大和最高性能的方法可能是构建find命令。

#!/usr/bin/env bash

# first argument is the directory name to search in
dir=$1; shift

# subsequent arguments are filenames to absolve from deletion
find_args=( )
for name; do
  find_args+=( -name "$name" -prune -o )
done

if [[ $dry_run ]]; then
  exec find "$dir" -mindepth 1 -maxdepth 1 "${find_args[@]}" -print
else
  exec find "$dir" -mindepth 1 -maxdepth 1 "${find_args[@]}" -exec rm -f -- '{}' +
fi

此后,列出要删除的文件(如果上面的文件位于名为delete-except的脚本中):

dry_run=1 delete-except /path/to/dir 1.txt 2.txt

或者,实际删除这些文件:

delete-except /path/to/dir 1.txt 2.txt

答案 1 :(得分:1)

一种简单,直接的方法可能是使用GLOBIGNORE变量。

GLOBIGNORE是一个以冒号分隔的模式列表,用于定义路径名扩展要忽略的文件名集。如果路径名扩展模式匹配的文件名也与GLOBIGNORE中的某个模式匹配,则会从匹配列表中删除它。

因此,解决方案是遍历命令行args,将文件名附加到列表中。然后拨打rm *。不要忘记在最后取消设置GLOBIGNORE var。

#!/bin/bash

for arg in "$@" 
do
    if [ $arg = $1 ]
    then
        GLOBIGNORE=$arg
    else
        GLOBIGNORE=${GLOBIGNORE}:$arg
    fi
done

rm *
unset GLOBIGNORE

*如果你以前设置了GLOBIGNORE,你可以将val存储在tmp var中,然后在最后重置它。

答案 2 :(得分:1)

我们可以在纯Bash中完成此任务,而无需任何外部工具:

#!/usr/bin/env bash

# build an associative array that contains all the filenames to be preserved
declare -A skip_list
for f in "$@"; do
  skip_list[$f]=1
done

# walk through all files and build an array of files to be deleted
declare -a rm_list
for f in *; do                          # loop through all files
  [[ -f "$f" ]]            || continue  # not a regular file
  [[ "${skip_list[$f]}" ]] && continue  # skip this file
  rm_list+=("$f")                       # now it qualifies for rm
done

# remove the files
printf '%s\0' "${rm_list[@]}" | xargs -0 rm -- # Thanks to Charles' suggestion

此解决方案也适用于包含空格或全局字符的文件。

答案 3 :(得分:-1)

感谢大家的回答,我已经找到了解决方案。以下是适合我的解决方案:

find /home/mydir -type f | grep -vw "goo" | xargs rm