代码之家  ›  专栏  ›  技术社区  ›  uvett

Bash中的双引号与星号文件名扩展

  •  5
  • uvett  · 技术社区  · 13 年前

    在目录中 ~/temp/a/foo/ 和 ~/temp/b/foo foo/ 我有一些名为 bar1 , bar2 , bar bar1 , bar bar2 等

    我正试图写一行Bash,将所有这些文件复制到一个目录中,该目录包含“foo”作为名称的最后一部分,并将其复制到相应“foo”文件夹上方的文件夹中。

    只要文件名中没有空格,这是一项简单的任务,但以下两个命令在处理 foo foo 目录:

    for dir in `find . -type d -name '*foo'` ; do cp $dir/* "$(echo $dir|sed 's_foo__g')" ; done
    

    ( cp 命令无法查看最后一个 foo 属于 "foo foo" 作为同一目录名的一部分。)

    for dir in `find . -type d -name '*foo'` ; do cp "$dir/*" "$(echo $dir|sed 's_foo__g')" ; done
    

    ( "$dir/*" 未展开。)

    尝试更换 $dir/* 具有 "$(echo $dir/*)" 甚至没有那么成功。

    有没有一种简单的扩展方法 $dir(美元)/* 因此 内容提供商 明白吗?

    3 回复  |  直到 13 年前
        1
  •  4
  •   Charles Duffy    13 年前

    不仅是 for 循环错误-- sed 也不是这项工作的合适工具。

    while IFS= read -r -d '' dir; do
      cp "$dir" "${dir/foo/}"
    done < <(find . -type d -name '*foo' -print0)
    

    使用 -print0 上 find (以及 IFS= read -r -d '' )确保带有换行符的文件名不会把你搞砸。

    使用 < <(...) 构造确保,如果循环内部设置变量、更改目录状态或做类似的事情,这些更改将继续存在(管道的右侧位于bash中的子shell中,因此管道进入while循环意味着在while循环中对shell状态所做的任何更改都将在退出时丢弃)。

    使用 ${dir/foo/} 比调用要高效得多 sed公司 ,就像bash内部的字符串替换一样。

        2
  •  2
  •   janos slartidan    13 年前

    这里的问题不在于 cp ,但带有 for ,因为默认情况下,它会按单词而不是按目录名来分割子shell的输出。

    一个懒惰的变通方法是使用 while 而是逐行处理目录列表,如下所示:

    find . -type d -name '*foo' | while read dir; do cp "$dir"/* "$(echo $dir | sed 's_foo__g')" ; done
    

    这应该可以解决你的空间问题,但这绝不是一个万无一失的解决方案。

    请参阅Charles Duffy的答案以获得更准确的解决方案。

        3
  •  0
  •   piokuc    13 年前

    重命名 ~/temp/b/foo foo/ 指没有空格的东西,例如。 ~/temp/b/foo_foo/ 然后再做你想做的事。在那之后,如果你真的必须的话,你可以用空格将其重命名回原来的文件名。顺便说一句,我从不使用包含空格的文件名,只是为了避免像你现在面临的那样复杂。