“mkdir foo; svn mv * foo”

“mkdir foo; svn mv * foo”

我经常想做这个习语的一些变体:

$ mkdir 2010
$ svn mv * 2010

当然,我收到错误,因为 glob 也匹配 2010:

svn: Cannot copy path '2010' into its own child '2010/2010'

有没有一种方法可以"svn mv * 2010"用不同的单衬来代替,从而起到正确的作用?

答案1

在 ksh、bash 或 zsh 下:

svn mv !(2010) 2010

在 bash 下,您需要shopt -s extglob先运行(将其放入您的~/.bashrc)。在 zsh 下,您需要setopt -o ksh_glob先运行(将其放入您的~/.zshrc)。

这不会移动点文件(名称以 开头的文件.)。如果有,请将它们分开移动。.svn如果有目录,请注意排除该目录。在 ksh 或 zsh 中:

svn mv !(2010) .!(svn) 2010

在 bash 中,这更加复杂,因为您还需要显式排除...

svn mv !(2010) .!(svn|.|) 2010

Zsh 还有一种不同的、更短的语法,需要setopt -o extended_glob首先运行(再次将其放入~/.zshrc):

svn mv {^,}2010

第一个大括号扩展开始发挥作用,导致svn mv ^2010 2010.然后该模式(“文件匹配但不匹配”^2010的快捷方式)被展开。*2010

如果您有.svn目录,则需要将其从移动中排除。默认情况下这是可以的,因为与(它是一个点文件).svn不匹配。*然而,也存在一些并发症:

  • 如果您设置了该glob_dots选项,则还需要排除.svn

    svn mv !(2010|.svn) 2010             # requires setopt ksh_glob
    svn mv *~(.svn|2010) 2010            # requires setopt extended_glob
    
  • 如果您有点文件并且尚未设置glob_dots,则需要单独移动它们:

    svn mv {^,}2010
    svn mv .*~.svn 2010
    

    一次性完成:

    svn mv *~(.svn|2010)(D) 2010
    

在这种情况下(如果没有子目录),在 zsh 中工作的另一种方法是svn mv *(.D) 2010仅匹配常规文件 ( .),包括点文件 ( D)。

答案2

ZSH 有一个有用的全局运算符来匹配除给定名称 之外的所有内容^。所以这可以工作(但它是 ZSH 特定的,你需要setopt extendedglob首先):

$ svn mv ^2010 2010

答案3

如果您的文件具有“驯服”名称(没有空格、不可打印字符或\[?*):

svn mv $(ls | grep -vx 2010) 2010

相关内容