首页 > 解决方案 > `cat` 命令的正确语法和用法?

问题描述

(这个问题是这个评论的后续,在关于 git hooks 的回答中)

我在 bash 方面(到目前为止)太不熟练了,无法完全理解这句话以及如何采取相应的行动。更具体地说,有人建议我避免以cat这种方式使用 bash 命令:

echo "$current_branch" $(cat "$1") > "$1"

因为操作的顺序取决于特定的shell,它最终可能会破坏传递参数的内容,所以如果我做对了,提交消息本身?

另外,如何“将内容保存在单独的步骤中”?

以下有什么意义吗?

tmp = "$1"
echo "$current_branch" $(cat $tmp) > "$1"

标签: bashcat

解决方案


提议的问题不是关于覆盖变量或参数,而是关于同时读取和写入文件通常是一个坏主意的事实。

例如,此命令可能看起来只是将文件写入自身,但实际上会截断它:

cat myfile > myfile   # Truncates the file to size 0

但是,这在您的特定命令中不是问题。它保证可以在符合 POSIX 的 shell 中工作,因为操作顺序指定重定向将扩展之后发生:

  1. 不是变量赋值或重定向的词应被扩展。如果扩展后仍有任何字段,则第一个字段应视为命令名称,其余字段是命令的参数。

  2. 重定向应按照重定向中的描述执行。

但是,从看似无害的修改可能引发问题的意义上说,它仍然有点脆弱,例如如果您想sed在结果上运行。由于重定向 ( > "$1") 和命令替换$(cat "$1")现在在单独的命令中,POSIX 定义不再为您节省:

# Command may now randomly result in the original message being deleted
echo "$current_branch $(cat "$1")" | sed -e 's/(c)/©/g' > "$1"

同样,如果你将它重构为一个函数,它也会突然停止工作:

# Command will now always delete the original message
modify_message() {
  echo "$current_branch $(cat "$1")"
}
modify_message "$1" > "$1"

您可以通过写入临时文件来避免这种情况,然后替换您的原始文件。

tmp=$(mktemp) || exit
echo "$current_branch $(cat "$1")" > "$tmp"
mv "$tmp" "$1"

推荐阅读