Shell文件名模式,可扩展为点文件,但不扩展为`..`?


13

最近,我因外壳模式以意外方式扩展而引起了一些意外。我想更改/root目录中一堆点文件的所有者,所以我做了

chown -R root .*

自然地,.*扩展到..那里确实是一场灾难。

我知道bash可以通过调整一些shell选项来更改此行为,但是在默认设置下,是否存在任何模式可以扩展到目录中的每个点文件,但不能扩展为.and ..

Answers:


20

Bash,ksh和zsh有更好的解决方案,但是在这个答案中,我假设使用POSIX shell。

该模式.[!.]*匹配所有以点后跟非点字符开头的文件。(请注意,[^.]某些外壳程序(但并非所有外壳程序都支持[!.]),通配符模式中字符集补码的可移植语法为。)因此,它排除了...,而且还排除了以两个点开头的文件。该模式..?*处理以两个点开头并且不只是的文件..

chown -R root .[!.]* ..?*

这是设置为匹配所有文件的经典模式:

* .[!.]* ..?*

这种方法的局限性在于,如果其中一种模式不匹配,则将其传递给命令。在脚本中,当您要匹配目录中除.和以外的所有文件时..,有几种解决方案,它们都很麻烦:

  • 使用* .*枚举所有条目,并排除...在一个循环。一个或两个模式可能都不匹配,因此循环需要检查每个文件的存在。您有机会根据其他条件进行过滤;例如,-h如果要跳过悬挂的符号链接,请删除测试。

    for x in * .*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • 一个更复杂的变体,其中命令仅运行一次。请注意,位置参数是很麻烦的(POSIX外壳没有数组)。如果存在问题,请将其放在单独的函数中。

    set --
    for x in * .[!.]* ..?*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      set -- "$@" "$x"
    done
    somecommand "$@"
  • 使用* .[!.]* ..?*三联画。同样,一个或多个模式可能不匹配,因此我们需要检查现有文件(包括悬挂的符号链接)。

    for x in * .[!.]* ..?*; do
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • 使用* .[!.]* ..?*tryptich,然后对每个模式运行一次命令,但前提是它匹配某些内容。这只会运行一次命令。请注意,位置参数很麻烦(POSIX外壳没有数组),如果存在问题,请将其放在单独的函数中。

    set -- *
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- .[!.]* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- ..?* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    somecommand "$@"
  • 使用find。使用GNU或BSD find,使用选项-mindepth和可以轻松避免递归-maxdepth。使用POSIX find,这有点棘手,但是可以做到。这种形式的优点是可以轻松地允许一次运行该命令,而不是每个文件一次(但不能保证:如果生成的命令太长,则该命令将分批运行)。

    find . -name . -o -exec somecommand {} + -o -type d -prune

6

如果所有文件名均包含至少三个字符(包括点),则此方法有效:

chown -R root .??*

要获得更强大的解决方案,可以使用find

find . -maxdepth 1 -name '.*' -exec chown -R root {} \;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.