从命令输出构建文件名会导致不明确的重定向错误
Building filename from command outputs results in ambigous redirect error
我想编辑一个文件并将其写入另一个位置,最后没有 .template。为此,我连续使用了两个命令,它们应该给我新的文件名,但 bash 不接受它。我听说你应该用反引号来做到这一点,但我无法让它工作(第一个 sed 是正确的,不要打扰):
sed -E '/^\s*(#.*)?$/d; s/^\s*(\S+)\s+("([^"]*)"|(\S+)).*/s\/\/\/g/' "$file" > `$(basename $file) | sed -E 's/(.*).template$/.translated/g')`
我收到这样的错误:
translate: command substitution: line 25: syntax error near unexpected token `)'
translate: command substitution: line 25: `$(basename $file) | sed -E 's/(.*).template$/.translated/g')'
translate: line 25: `$(basename $file) | sed -E 's/(.*).template$/.translated/g')`: ambiguous redirect
重定向到文件名部分应该是什么样的?
第 1 部分:为什么会发生
让我们看看为什么您会收到“不明确的重定向”错误。
当你运行:
foo > `$(basename $file) | sed -E 's/(.*).template$/.translated/g')`
...这是告诉 shell 首先 运行 一个命令:
$(basename $file) | sed -E 's/(.*).template$/.translated/g'
...并将其输出用作重定向目标。
但是,$(basename $file) | ...
与basename $file | ...
不一样!假设您的文件名为 /path/to/foo.template
。在第一个命令替换发生后,它被翻译成:
foo.template | sed -E 's/(.*).template$/.translated/g'
...这是 运行宁 一个名为 foo.template
的命令并将其输出提供给 sed
.
你有一个名为foo.template
的命令吗?如果不这样做,那么只会在 stderr 上产生错误,而在 stdout 上什么也没有。由于 stdout 是输入 sed
的内容,这意味着 sed
根本没有接收到任何输入,所以它 写入 根本没有输出,所以你有一个空文件名。
并试图重定向到一个空文件名...是不明确的!这是你的错误。
第 2 部分:正确行事
我假设您的 sed
命令都执行您希望它们执行的操作(这意味着您 想要 foo.template
创建一个名为 .footranslated
-- 如果你不想创建这个隐藏文件,你的第二个sed
操作就大错特错了。
file_base=${file##*/}
sed -E '/^\s*(#.*)?$/d; s/^\s*(\S+)\s+("([^"]*)"|(\S+)).*/s\/\/\/g/' "$file" \
>".translated${file_base%.template}"
...或者,如果您的实际意图是将扩展名 .template
替换为扩展名 .translated
,则应该是:
file_base=${file##*/}
sed -E '/^\s*(#.*)?$/d; s/^\s*(\S+)\s+("([^"]*)"|(\S+)).*/s\/\/\/g/' "$file" \
>"${file_base%.template}.translated"
我想编辑一个文件并将其写入另一个位置,最后没有 .template。为此,我连续使用了两个命令,它们应该给我新的文件名,但 bash 不接受它。我听说你应该用反引号来做到这一点,但我无法让它工作(第一个 sed 是正确的,不要打扰):
sed -E '/^\s*(#.*)?$/d; s/^\s*(\S+)\s+("([^"]*)"|(\S+)).*/s\/\/\/g/' "$file" > `$(basename $file) | sed -E 's/(.*).template$/.translated/g')`
我收到这样的错误:
translate: command substitution: line 25: syntax error near unexpected token `)'
translate: command substitution: line 25: `$(basename $file) | sed -E 's/(.*).template$/.translated/g')'
translate: line 25: `$(basename $file) | sed -E 's/(.*).template$/.translated/g')`: ambiguous redirect
重定向到文件名部分应该是什么样的?
第 1 部分:为什么会发生
让我们看看为什么您会收到“不明确的重定向”错误。
当你运行:
foo > `$(basename $file) | sed -E 's/(.*).template$/.translated/g')`
...这是告诉 shell 首先 运行 一个命令:
$(basename $file) | sed -E 's/(.*).template$/.translated/g'
...并将其输出用作重定向目标。
但是,$(basename $file) | ...
与basename $file | ...
不一样!假设您的文件名为 /path/to/foo.template
。在第一个命令替换发生后,它被翻译成:
foo.template | sed -E 's/(.*).template$/.translated/g'
...这是 运行宁 一个名为 foo.template
的命令并将其输出提供给 sed
.
你有一个名为foo.template
的命令吗?如果不这样做,那么只会在 stderr 上产生错误,而在 stdout 上什么也没有。由于 stdout 是输入 sed
的内容,这意味着 sed
根本没有接收到任何输入,所以它 写入 根本没有输出,所以你有一个空文件名。
并试图重定向到一个空文件名...是不明确的!这是你的错误。
第 2 部分:正确行事
我假设您的 sed
命令都执行您希望它们执行的操作(这意味着您 想要 foo.template
创建一个名为 .footranslated
-- 如果你不想创建这个隐藏文件,你的第二个sed
操作就大错特错了。
file_base=${file##*/}
sed -E '/^\s*(#.*)?$/d; s/^\s*(\S+)\s+("([^"]*)"|(\S+)).*/s\/\/\/g/' "$file" \
>".translated${file_base%.template}"
...或者,如果您的实际意图是将扩展名 .template
替换为扩展名 .translated
,则应该是:
file_base=${file##*/}
sed -E '/^\s*(#.*)?$/d; s/^\s*(\S+)\s+("([^"]*)"|(\S+)).*/s\/\/\/g/' "$file" \
>"${file_base%.template}.translated"