1

我发现了几个有解决方案的类似问题,除了它们不涉及变量。

我在文件和目录树中有一个特定的模式 - 模式是单词 TEMPLATE。我想要一个脚本文件通过将单词 TEMPLATE 替换为变量 ${newName} 中包含的其他名称来重命名所有文件和目录

如果我知道 ${newName} 的值是“弗雷德住在这里”,那么命令

find . -name '*TEMPLATE*' -exec bash -c 'mv "$0" "${0/TEMPLATE/Fred lives here}"' {} \;

会做这项工作

但是,如果我的脚本是:

newName="Fred lives here"
find . -name '*TEMPLATE*' -exec bash -c 'mv "$0" "${0/TEMPLATE/${newName}}"' {} \;

然后单词 TEMPLATE 被替换为 null 而不是“Fred 住在这里”

我需要 $0 左右的 "" 因为路径名中有空格,所以我不能做类似的事情:

find . -name '*TEMPLATE*' -exec bash -c 'mv "$0" "${0/TEMPLATE/"${newName}"}"' {} \;

谁能帮我让这个脚本工作,以便所有包含单词 TEMPLATE 的文件和目录都将 TEMPLATE 替换为任何${newName}

例如,如果newName="A different name"我有一个目录

/foo/bar/some TEMPLATE directory/with files然后目录将被重命名为

/foo/bar/some A different name directory/with files

并且一个名为的文件some TEMPLATE file将被重命名为

some A different name file

4

2 回答 2

2

你不必使用引号,IFS=$'\n'因为bash -c它是一个子shell export,任何变量都是必需的。这有效:

#!/bin/bash
IFS=$'\n'
export newName="Fred lives here"
find . -name '*TEMPLATE*' -exec bash -c 'mv "$0" "${0/TEMPLATE/${newName}}"' {} \;

如果您不介意再增加两行代码,并且想要一个更易于阅读的脚本(无需导出):

#!/bin/bash
IFS=$'\n'
newName="Fred lives here"
for file in $(find . -name '*TEMPLATE*'); do
    mv ${file} ${file/TEMPLATE/${newName}}
done
于 2013-11-05T05:15:56.093 回答
1

你有两个选择。

1)最简单的解决方案是export newName。如果您不导出变量,则它在子shell 中不可用,并且bash -c是子shell。这就是为什么你会TEMPLATE被什么都取代。

2) 或者,您可以尝试构造一个正确引用的命令行,其中包含$newName. 如果您知道它$newName表现得相当好(例如,没有双引号或美元符号),那么这很容易:

find . -name '*TEMPLATE*' \
       -exec bash -c 'mv "$0" "${0/TEMPLATE/'"${newName}"'}"' {} \;

(注:bash 引用充满了微妙之处。以下已编辑多次,但我认为现在是正确的。)

但是由于您不能指望这一点,您可能需要通过将文件名和替换都替换为命令行参数来构造命令行。但在我们这样做之前,让我们修复$0. 您不应该将其$0用作参数。正确的语法是:

bash -c '...$1...$1...' bash "argument"

注意额外的bash(很多人喜欢使用_);它可以为子流程提供一个合理的名称。

所以考虑到这一点:

find . -name '*TEMPLATE*' \
       -exec bash -c 'mv "$1" "${1/TEMPLATE/$2}"' bash {} "$newName" \;
于 2013-11-05T04:00:19.200 回答