如何显示包含两个字符且其中之一是 c 的文件名?

如何显示包含两个字符且其中之一是 c 的文件名?

我尝试这样做ls [a-z][a-z],但似乎不起作用。

答案1

使用 bash,设置 glob 设置,以便丢失的匹配项不会触发错误:

shopt -u failglob  # avoid failure report (and discarding the whole line).
shopt -s nullglob  # remove (erase) non-matching globs.
ls ?c c?

问号是代表单个字符的全局字符。由于您需要两个字符的文件名,因此其中一个必须是 a c,因此它要么是第一个字符,要么是最后一个字符。

这样shopt -s dotglob还会出现一个名为.c.

如果没有匹配的文件,设置这些 shell 选项会导致所有参数被删除,从而导致默认ls列出任何内容/所有内容。

改用这个:

shopt -s nullglob  ## drop any missing globs
set -- ?c c?       ## populate the $@ array with (any) matches
if [ $# -gt 0 ]    ## if there are some, list them
  ls -d "$@"
fi

答案2

我认为更好的方法是使用find

find . -type f -name '*c*' -name '??'

这将递归搜索。仅列出当前目录中的文件:

find . ! -name . -prune  -type f -name '*c*' -name '??'

答案3

如果文件存在(并且没有转义字符,例如\c),则可以使用 glob:

echo ?c c?

它将匹配包含一个字符 ( ?) 后跟一个字符的文件c或包含c一个字符后跟一个字符 ( ?) 的文件。

但会因文件而失败名字以破折号(如-nor 或)开头-e,并以反斜杠字符(如\cor \nwith echoas 两者)开头-e,并且-n对于(某些 shell)是特殊的echo,并且\cor\n将被解释为转义序列(\c结束输出并打印新行,而不是某些 shell 实现中的\n逐字字符设置\n选项时使用 echo 和 bash )。shopt -s xpg_echo其他应用程序或实用程序(例如ls)将具有一些其他选项,并且可能会因许多其他破折号开头或解释文件名中的其他转义字符而失败。

还将列出一个名为cc两次的文件。

  • 如果文件可能以破折号开头(如 -n),请使用:

    $ ls -d -- ?n 
    -n 
    

    或更好:

    $ ls -d ./?n
    ./-n
    

注意事项

  • 全局匹配没有文件。

    1. 如果文件不存在,则不会扩展 glob,并且会以其原始形式打印 glob。

      $ echo ?m m?
      ?m m?
      
    2. 除了 zsh 之外。

      $ zsh -c 'echo ?m m?'
      zsh:1: no matches found: ./m?
      

      shell 将退出并出现错误。
      此行为由兹什的nomatch选项。

      $ zsh -c 'setopt +o nomatch; echo ?m m?'
      ?m m?
      

      或者:

      $ zsh -c 'echo ?m(N) m?(N)'
      ?m m?
      

      但这会打印mm两次。

    3. failglob在 bash 中,如果设置了shell 选项,您可以获得与 zsh 类似的结果:

      $ bash -c 'shopt -s failglob; echo ?m m?'
      bash: no match: ?m
      

      但脚本不会停止,shell也不会退出。好吧,从技术上讲,使用 glob 的行不会进一步执行,而是在下一个脚本行继续执行。

    4. 在 bash 中,您可以设置选项nullglob来删除不匹配的 glob:

      $ bash -c 'shopt -s nullglob; echo ?m m? done'
      done
      
  • 使用 ls (与其他程序类似)

    1. 匹配文件不会有问题,但也会匹配(并列出)目录:

      $ ls ?c c?
      bc  cz  sc
      
      ac:
      hjk
      

      更好地使用-dwith ls(目录将被包含但不扩展)。

      $ ls -d ?c c?
      ac bc cz sc
      
    2. Glob 无法匹配文件(或目录)

      然后ls会报失败

      $ ls ?m m?
      ls: cannot access '?m': No such file or directory
      

      其他程序可能(可能)这样做不是做类似的检查。

    3. 与 bash 一起使用nullglob会给 ls 一个空列表,因此,它将列出内容或 pwd,就好像只ls执行了一样:

      $ ls ?m m?
      ac a.out cz 3 b sc ab bc
      

      这可以避免使用./

      $ ls -d ./?m ./m?
      ls: cannot access './?m': No such file or directory
      ls: cannot access './m?': No such file or directory
      

或者您可以使用查找正则表达式(但它将遍历prune缺少的子目录)(请注意,这不会重复名为 cc 的文件):

    $ find . ! -name . -prune -regex '.*/\(.c\|c.\)'
    ./ac
    ./cc
    ./sc
    ./bc
    ./cz

答案4

bash

  • 后跟c字符 ( ?c) 或字符(包括.dotglob后跟c( ?c)。

    shopt -s extglob failglob dotglob
    printf '%s\n' @(?c|c?)
    
  • 除不包含c( !(*c*)) 或不是两个字符 ( !(??)) 的文件之外的所有文件。这里使用双重否定来实现合取。

    shopt -s extglob failglob dotglob
    printf '%s\n' !(!(*c*)|!(??))
    

zsh

  • printf '%s\n' (?c|c?)(D)

    (其中D启用dotglob; failglobnomatch在 中调用zsh)默认情况下处于启用状态)。

  • 双重否定使用~ 除了运算符和^否定扩展运算符:

    set -o extendedglob
    printf '%s\n' *c*~^??(D)
    

ksh93

  • ksh93 中没有nomatch/failglob选项,但您可以在那里手动完成:

    FIGNORE='@(.|..)' # only ignore . and .. and not the other dotfiles
    files=(~(N)@(?c|c?))
    if ((${#files[@]})); then
      printf '%s\n' "${files[@]}"
    else
      echo >&2 No match
      exit 1
    fi
    

    (其中~(N)启用nullglob该全局)。

  • ksh93确实有一个合取运算符。所以在这里,您还可以将该files=(...)行更改为:

    files=(~(N)@(*c*&??))
    

相关内容