【问题标题】:Shell - Write variable contents to a fileShell - 将变量内容写入文件
【发布时间】:2012-07-22 01:15:57
【问题描述】:

我想将一个变量(这里称为var)的内容复制到一个文件中。

文件名存储在另一个变量destfile 中。

我在执行此操作时遇到问题。这是我尝试过的:

cp $var $destfile

我也用 dd 命令尝试过同样的事情……显然 shell 认为 $var 指的是一个目录,所以告诉我找不到该目录。

我该如何解决这个问题?

【问题讨论】:

  • 请通过发布一些properly formatted 代码来改进您的问题,这些代码显示了您如何填充变量,以及所有相关错误消息与它们完全一样。
  • “复制变量的内容”到目录是什么意思? $var 是否指定了应写入文件的文件名或某些文本?如果它指定文本,那么您要写入此内容的文件的名称是什么?
  • $var 包含我要复制的文本,并且应该写入的文件是用户定义的,因此我首先使用变量的原因。
  • 也许$destdir 应该命名为$destfile,这样才不会产生误导... $destdir 这个名称表明它指定了一个目录而不是一个文件。这将使您的整个问题变得简单易懂。

标签: linux bash shell


【解决方案1】:

上述所有工作,但还必须解决一个不需要首先出现的问题(转义和特殊字符):shell 扩展变量时的特殊字符。只是首先不要这样做(变量扩展)。直接使用变量,不展开。

此外,如果您的变量包含一个秘密并且您想将该秘密复制到一个文件中,您可能不希望在命令行中进行扩展,因为 shell 命令的跟踪/命令回显可能会泄露该秘密。意味着,所有在命令行中使用$var 的答案都可能通过将变量内容暴露给shell 的跟踪和日志记录而存在潜在的安全风险。

对于已经导出的变量,使用这个:

printenv var >file

这意味着,如果是 OP 问题:

printenv var >"$destfile"

注意:变量名区分大小写。

警告:为了使用 printenv 打印而导出变量并不是一个好主意。如果您有一个包含机密的未导出脚本变量,导出它会将其公开给所有未来的子进程(除非未导出,例如使用export -n)。

【讨论】:

  • 这应该是公认的答案。它正确回答了 OP 的问题,没有潜在的危险副作用。它唯一的缺点是它不是一个内置的 shell,即使你几乎可以在每个 linux 机器上找到它。我只想指出它是区分大小写的。 printenv user 不打印任何内容,而 printenv USER 打印当前用户名(至少在我的计算机上)。
  • 是的,Unix (POSIX/Linux) 上的环境是区分大小写的,就像(几乎?)其他一切一样。添加了注释。谢谢。
  • 这应该是公认的答案。它也适用于像 Jenkins 中那样的“太聪明而不利于他们自己”的逃避例程。
  • 这仅适用于环境变量,不适用于本地脚本的变量。您必须export 这些变量,并且如果您的值包含任何秘密,这意味着以相同用户身份运行的任何进程都可以从进程表中读取这些值,并且所有子进程也将继承这些值,可能会将信息泄漏到您未预料到的其他进程。不是理想的情况。使用printf "$var"foo <<< "$var" 应该适用于所有情况。
  • 感谢@LieRyan,这是一个很好的观点,我已经相应地更新了答案。请注意,启用命令回显或跟踪时,您的建议可能会将变量值泄漏到日志中。
【解决方案2】:

如果您的变量,上述答案均无效:

  • -e开头
  • -n开头
  • -E开头
  • 包含一个\,后跟一个n
  • 不应在其后附加额外的换行符

因此不能依赖它们来获取任意字符串内容。

在 bash 中,您可以将“这里的字符串”用作:

cat <<< "$var" > "$destdir"

正如 Ash 在下面的评论中指出的,@Trebawa's answer(与我在同一个房间里制定!)使用 printfcat 更好。

【讨论】:

  • 据我所知,cat 总是会在文件末尾插入换行符,无论变量末尾没有换行符(尽管可以说这在大多数情况下是件好事例)。 answer using printf 似乎避免插入尾随换行符。
  • @Ash printf 相对于cat 的另一个优势是前者是一个内置的shell,它的执行速度总是比外部二进制文件快。
【解决方案3】:

如果我没听错的话,你想将$var 复制到一个文件中(如果它是一个字符串)。

echo $var > $destdir

【讨论】:

  • 这就是它的完成方式。使用cp 命令将使shell 将第一个参数解释为文件或目录的名称。
  • 如果您不将$var 括在引号中,则在某些情况下文件的内容与$var 的内容不是100% 相等。例如,当“回显”包含 RSA 密钥的变量时,您会在文件中获得无效的密钥。
  • 如果$var 包含空格或-e 则失败
【解决方案4】:

echo 的问题是如果var 包含类似-e 的内容,它将被解释为一个标志。另一个选项是printf,但printf "$var" &gt; "$destdir" 将扩展变量中的任何转义字符,因此如果变量包含反斜杠,则文件内容将不匹配。但是,由于printf 仅将反斜杠解释为格式字符串中的转义,您可以使用%s 格式说明符将确切的变量内容存储到目标文件中:

printf "%s" "$var" &gt; "$destdir"

【讨论】:

  • printf 如果变量字符串中有换行符也很好,例如来自三引号或heredoc。 echo 不能很好地处理换行符。
  • @beeflobill 你能解释一下“echo 不能很好地处理换行符”吗?我唯一看到的是 echo 添加了一个换行符。这确实使echo "$var" &gt; destfile 错了。
  • @SensorSmith 在我的实验中,我看到当字符串有“\n”时,回显将打印一个换行符。但是,如果字符串有一个实际的换行符,则 echo 不会打印它。我不知道为什么。
  • 基本上是可移植性(和可靠性)问题。 unix.stackexchange.com/a/65819 ... 或者对于我们中间的致命者:printf 更好,继续前进。
  • 如果您,朝圣者,阅读此答案并考虑删除 $var 周围的双引号 - 停止它。在某些情况下,如果没有引号或单引号,它将无法工作。只需接受您必须使用双引号即可。这些知识让我花了一天时间来调试一个损坏的 GitHub Actions 工作流,在该工作流中我将一个私钥(带有换行符)从一个秘密保存到一个文件中……
【解决方案5】:

使用echo 命令:

var="text to append";
destdir=/some/directory/path/filename

if [ -f "$destdir" ]
then 
    echo "$var" > "$destdir"
fi

if 测试 $destdir 代表一个文件。

&gt; 在截断文件后附加文本。如果您只想将$var 中的文本附加到文件现有内容中,请改用&gt;&gt;

echo "$var" >> "$destdir"

cp 命令用于复制文件(到文件),而不是用于将文本写入文件。

【讨论】:

  • 需要更多引号 -- 现在,变量值中的任何空格都将转换为单个空格,glob 表达式将被扩展,等等。
  • 另外一件事——你需要在结束引号和"$destdir"] 中的] 之间留一个空格。
  • echo 还会在您的变量中添加一个尾随换行符。
  • 如果$var-e text to append 则失败,并且实际上并未写入-e
  • 因为echo $var 依赖于shell 来扩展你的变量,它对空格和特殊字符之类的东西不太适用。您可以改用perl -e 'print($ENV{var})',它会精确输出变量的值。
【解决方案6】:

当您说“复制变量的内容”时,该变量是包含文件名,还是包含文件名?

我假设您的问题 $var 包含您要复制到文件中的 内容

$ echo "$var" > "$destdir"

这会将 $var 的值回显到一个名为 $destdir 的文件中。注意引号。将“$var”括在引号中非常重要。如果名称中有空格,也适用于“$destdir”。要附加它:

$ echo "$var" >> "$destdir"

【讨论】:

  • 如果 var 包含 -e 则失败
  • 将双连字符作为第一个参数传递给echo 会终止其选项列表,从而解决@Eric 提出的问题:echo -- "$var" &gt;&gt; "$destfile"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-28
相关资源
最近更新 更多