有选择地返回文件列表

有选择地返回文件列表

上下文:OSX Catalina (zSh) 和 Ubuntu 16.04 (Bash)。 OSX 终端命令:

FILES="$PWD/*"  #list of files
echo $FILES

将所有文件的字符串返回到控制台。目前,我打算在要处理的目录中植入脚本的副本。将来,我希望让脚本能够接受要处理的参数(目录)。

假设工作目录中存在文件类型(扩展名而不是隐藏文件):

  • .abc
  • .ABC
  • .def
  • .ghi
  • .jkl
  • .sh

我对上述说明的修改示例感兴趣,这些示例将:

  1. 仅显式选择 .abc .ABC 和 .def 文件类型(扩展名)
  2. 选择所有文件除了.sh 和 .jkl

理想情况下会有一个命令选项来指定不区分大小写

答案1

您可以使用 bash 中的数组轻松完成此操作(这是 Ubuntu 上的默认 shell,macOS 的新版本是 bash 或 zsh;这些解决方案与 bash 相关):

  1. 选择所有文件(您的原始命令,稍作修改):

     $ shopt -s nullglob
     $ files=(*)
     $ echo "${files[@]}"
     file.abc file.ABC file.def file.ghi file.jkl file.sh
    

    nullglob如果目录为空,则打开该选项会给出一个空列表。如果没有此选项,如果目录为空,files则将是一个元素的列表,该元素是未展开的*.

  2. .abc仅选择名称以或.ABC或结尾的文件.def

    $ shopt -s nullglob
    $ files=(*.abc *.ABC *.def)
    $ echo "${files[@]}"
    file.abc file.ABC file.def
    
  3. 选择除名称以.sh或结尾的文件之外的所有文件.jkl

    $ shopt -s extglob nullglob
    $ files=(!(*.sh|*.jkl))
    $ echo "${files[@]}"
    file.abc file.ABC file.def file.ghi
    
    
  4. 不区分大小写的匹配

    $ shopt -s nocaseglob nullglob
    $ files=(*abc)
    $ echo "${files[@]}"
    file.abc file.ABC
    

另外,请注意您正在做什么。files="$PWD/*"不会将 的值设置$files为当前目录中的所有文件。它将其值设置为以 结尾的字符串/*

$ cd /tmp/current_directory
$ files="$PWD/*" 
$ echo "$files"
/tmp/current_directory/*

您认为它有效的原因是因为您使用的是echo $files未加引号的,这意味着 shell 正在扩展/tmp/current_directory/*。但是,如果您随后要删除这些文件,则相同的echo命令将简单地打印/tmp/current_directory/*$PWD扩展到您最初运行该命令的任何目录。文件列表不会与变量一起保存。像我在这里所做的那样使用数组可确保变量存储实际的文件列表,而不仅仅是可以根据使用位置扩展到不同值的 glob。

答案2

zsh

files=($PWD/*.(abc|ABC|DEF)(N))
print -rC1 -- $files # print raw, on one column.

(N)使用应用于nullglob该 glob 的限定符,使其$files成为模式的空列表与任何文件不匹配,而不是报告错误)。

对于.sh和以外的文件.jkl

set -o extendedglob # needed for the ^ negation operator
files=($PWD/^*.(sh|jkl)(N))

对于不区分大小写的匹配(.ABC/ .abc/ .Abc...):

set -o extendedglob
files=($PWD/*.(#i)abc(N))

你的:

FILES="$PWD/*"
echo $FILES

有几个帐户是错误的:

FILES="$PWD/*"不将文件列表存储在$FILE变量中。这是一个标量赋值,它只能存储一个值。相反,它存储在后面跟着字面意思$FILES的内容中。$PWD/*

在,echo $FILES如未$FILES引用的那样,在bash(但不是zsh)中, 的扩展$FILES受到 split+glob 的影响。就在那时,假设$FILES不包含任何字符$IFS(这将触发分裂部分),并且$PWD不包含通配符(这也会触发 glob 部分),该值将扩展到匹配文件列表。

在 中zsh, split+glob 并不是在参数扩展时隐式完成的,您需要显式地请求它们($=FILES对于分割,$~FILES对于通配符,$=~FILES对于两者)。

然后使用echo输出任意数据是错误的,echo默认情况下进行额外处理也是错误的(在 中zsh,您可以使用echo -E - $filesprint -r -- $files)。

相关内容