删除除配置文件中提到的文件以外的所有文件

时间:2017-03-16 13:49:27

标签: linux bash shell

情况:

我需要一个删除当前文件夹中所有文件的bash脚本,但名为“ .rmignore ”的文件中提到的所有文件除外。此文件可能包含相对于当前文件夹的地址,该地址也可能包含星号(*)。例如:

1.php
2/1.php
1/*.php

我尝试了什么:

  • 我尝试使用GLOBIGNORE,但效果不佳。
  • 我还尝试将findgrep一起使用,如下所示:

    find . | grep -Fxv $(echo $(cat .rmignore) | tr ' ' "\n")

6 个答案:

答案 0 :(得分:1)

这条线完美地完成了工作

find . -type f | grep -vFf .rmignore

答案 1 :(得分:1)

如果我们假设.rmignore中的所有文件都没有在其名称中包含换行符,则以下内容可能就足够了:

# Gather our exclusions...
mapfile -t excl < .rmignore

# Reverse the array (put data in indexes)
declare -A arr=()
for file in "${excl[@]}"; do arr[$file]=1; done

# Walk through files, deleting anything that's not in the associative array.
shopt -s globstar
for file in **; do
  [ -n "${arr[$file]}" ] && continue
  echo rm -fv "$file"
done

注意:未经测试。 :-)此外,关联数组与Bash 4一起引入。

另一种方法可能是使用整个文件列表填充数组,然后删除排除项。如果您处理数十万个文件,这可能是不切实际的。

shopt -s globstar
declare -A filelist=()

# Build a list of all files...
for file in **; do filelist[$file]=1; done

# Remove files to be ignored.
while read -r file; do unset filelist[$file]; done < .rmignore

# Annd .. delete.
echo rm -v "${!filelist[@]}"

也未经测试。

警告:rm后果自负。可能含有坚果。保持备份。

我注意到这些解决方案都不会处理.rmignore文件中的通配符。为此,您可能需要一些额外的处理......

shopt -s globstar
declare -A filelist=()

# Build a list...
for file in **; do filelist[$file]=1; done

# Remove PATTERNS...
while read -r glob; do
  for file in $glob; do
    unset filelist[$file]
  done
done < .rmignore

# And remove whatever's left.
echo rm -v "${!filelist[@]}"

而且......你猜对了。未经测试。这取决于$f扩展为glob。

最后,如果您需要更重的解决方案,可以使用findgrep

find . -type f -not -exec grep -q -f '{}' .rmignore \; -delete

这会为正在考虑的EACH文件运行grep。而且它不是一个bash解决方案,它只依赖find这是非常普遍的。

请注意,如果您的文件包含换行符,则所有这些解决方案都存在错误风险。

答案 2 :(得分:1)

find的出口传递给另一个命令被认为是不好的做法。您可以使用-exec-execdir后跟命令,'{}'作为文件的占位符,';'表示命令结束。您还可以使用'+'将命令组合在一起IIRC。

在您的情况下,您希望列出目录的所有争议,并逐个删除文件。

#!/usr/bin/env bash

set -o nounset
set -o errexit
shopt -s nullglob # allows glob to expand to nothing if no match
shopt -s globstar # process recursively current directory

my:rm_all() {
    local ignore_file=".rmignore"
    local ignore_array=()
    while read -r glob; # Generate files list
    do
        ignore_array+=(${glob});
    done < "${ignore_file}"
    echo "${ignore_array[@]}"

    for file in **; # iterate over all the content of the current directory
    do
        if [ -f "${file}" ]; # file exist and is file
        then
            local do_rmfile=true;
            # Remove only if matches regex
            for ignore in "${ignore_array[@]}"; # Iterate over files to keep
            do
                [[ "${file}" == "${ignore}" ]] && do_rmfile=false; #rm ${file};
            done

            ${do_rmfile} && echo "Removing ${file}"
        fi
    done
}

my:rm_all;

答案 3 :(得分:0)

如果您有temp\formats.sas7bcat,则可以使用合适的rsync忽略文件将空目录复制到目标目录。首先使用rsync尝试一下,看看它会尝试什么,然后再运行它!

答案 4 :(得分:0)

这是另一个bash解决方案,似乎在我的测试中正常工作:

intent

Test it online here

答案 5 :(得分:0)

或者,您可能希望查看最简单的格式:

rm $(ls -1 | grep -v .rmignore)