如何删除目录中除了几个选定文件之外的所有文件?

问题描述 投票:2回答:4

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

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

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

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

linux bash unix
4个回答
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
投票

一种简单,直接的方法可能是使用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中,然后在最后重置它。


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

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


-1
投票

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

find /home/mydir -type f | grep -vw "goo" | xargs rm 
© www.soinside.com 2019 - 2024. All rights reserved.