获取除数组中的文件之外的所有文件 - Bash

获取除数组中的文件之外的所有文件 - Bash

我需要编写一个一次性实用程序,它对给定目录中的所有文件(但预定义列表中的文件列表)执行一些操作。由于给定的列表是预定义的,我将把它硬编码为数组。

话虽如此,如何获取不在给定数组中的所有文件的名称?这可以是任何标准的 unix 脚本(bash、awk、perl)。

答案1

有了bash,你可以这样做:

all=(*)
except=(file1 file2 notme.txt)
only=()
IFS=/
for file in "${all[@]}"; do
  case "/${except[*]}/" in
    (*"/$file/"*) ;;     # do nothing (exclude)
    (*) only+=("$file")  # add to the array
  esac
done
ls -ld -- "${only[@]}"

(这适用于当前目录中的文件,但对于像all=(*/*) except=(foo/bar)我们用来/连接数组元素以进行查找的全局变量来说并不可靠)。

它基于以下事实:"${array[*]}"将数组的元素与$IFS(此处选择的第一个字符连接起来,/因为它不会出现在文件中姓名; NUL是文件中不能出现的字符小路,但不幸的是bash(与 相反zsh)它的变量中不能有这样的字符)。因此,对于其中的每个文件$all(此处以$filebeingfoo为例),我们都会case "/file1/file2/notme.txt/" in (*"/foo/"*)检查是否$file要排除。

答案2

使用以下方法更容易zsh

except=(file1 file2 notme.txt)
all=(*)
only=(${all:|except})
ls -ld -- $only

助记符${all:|except}:元素$all 酒吧那些$except.

您还可以检查文件是否在数组中$except作为全局限定符

ls -ld -- *.txt(^e:'((except[(Ie)$REPLY]))':)

或者使用一个函数:

in_except() ((except[(Ie)${1-$REPLY}]))
ls -ld -- *.txt(^+in_except)

答案3

如果文件名足够简单,您可以使用bash的GLOBIGNORE变量

shellGLOBIGNORE变量可用于限制与模式匹配的文件名集。如果GLOBIGNORE设置,GLOBIGNORE则将从匹配列表中删除也与其中模式之一匹配的每个匹配文件名。如果nocaseglob设置了该选项,则执行与 中的模式的匹配GLOBIGNORE,而不考虑大小写。当设置且不为空时,文件名...始终被忽略 。GLOBIGNORE但是,设置GLOBIGNORE为非空值具有启用dotglobshell 选项的效果,因此以 ' ' 开头的所有其他文件名.都将匹配。要获得忽略以 ' ' 开头的文件名的旧行为.,请将 ' .*' 设为GLOBIGNORE.未设置时该dotglob选项将被禁用。GLOBIGNORE

$ echo *
bin boot dev etc home lib lib64 lost+found mnt opt proc root run sbin srv sys tmp usr var
$ except=(etc lib lib64 tmp sbin)
$ GLOBIGNORE=$(IFS=:; printf "%s" "${except[*]}")
$ echo *
bin boot dev home lost+found mnt opt proc root run srv sys usr var

当然,如果您正在创建数组,那么您可以直接设置变量GLOBIGNORE

GLOBIGNORE=etc:lib:lib64:tmp:sbin

您还可以利用列表中可能存在的任何适合 bash 通配符的模式:

GLOBIGNORE=etc:lib*:tmp:sbin

相关内容