【问题标题】:How to delay `redirection operator` of BASH `>`如何延迟BASH`>`的`重定向运算符`
【发布时间】:2021-03-15 18:30:18
【问题描述】:

首先我创建了 3 个文件:

$ touch alpha bravo carlos

然后我想将列表保存到文件中:

$ ls > info.txt

但是,我的info.txt 总是在里面:

$ 猫信息.txt α 好极了 卡洛斯 info.txt

看起来重定向运算符首先创建了我的info.txt

在这种情况下,我的问题是。在首先创建info.txt 之前如何保存我的文件列表?


主要问题是关于重定向运算符。为什么它先行动,以及如何延迟它以便我先完成我的任务?用上面的例子来回答。

【问题讨论】:

  • 这是一个常见的常见问题解答。无法在命令之后执行重定向,但您可以重定向到不同目录中的文件(例如,/tmp),然后将其移至此处。
  • 在哪里可以找到有关它的更多信息。它会影响其他操作吗?可以用 Python 或 C 等其他语言实现吗?
  • ls | tee info.txt >/dev/null 做你想做的事。我不会说它比 Tripleee 建议的更好,但它是一种替代方案。
  • 两个答案都很棒!我很感激!我从 90 年代开始就在使用计算机,但我仍然无法将每一块都安装到位,所以我需要更多时间来了解操作系统,我不知道“空字节”、进程如何工作或字符编码。所以有一个平局,我还没有足够的代表来支持你的答案。
  • 请注意,我在 Android 10 上的 Termux 中使用 Bash,我无权访问 / 或 /dev/null 中的任何内容,我也不希望这个问题成为Android 问题,因此任何 Linux/Bash 答案都是有效的。

标签: bash redirect operator-keyword


【解决方案1】:

当您将命令的输出重定向到文件时,shell 会打开一个指向目标文件的文件句柄,然后在标准输出连接到该文件句柄的子进程中运行该命令。无法更改此顺序,但如果您不希望 ls 输出包含新文件,则可以重定向到不同目录中的文件。

ls >/tmp/info.txt
mv /tmp/info.txt ./

在生产脚本中,您应该确保文件名是唯一且不可预测的。

t=$(mktemp -t lstemp.XXXXXXXXXX) || exit
trap 'rm -f "$t"' INT HUP 
ls >"$t"
mv "$t" ./info.txt

或者,将输出捕获到变量中,然后将该变量写入文件。

files=$(ls)
echo "$files" >info.txt

顺便说一句,可能don't use ls in scripts.如果你想要当前目录中的文件列表

printf '%s\n' *

这样做。

【讨论】:

  • 在执行重定向之前扩展 Glob,ls -d * >list.txt,或者更好的是,printf '%s\n' * >list.txt,也可以正常工作
  • @oguzismail 谢谢,更改了措辞。
【解决方案2】:

一种简单的方法是将命令输出保存到变量中,如下所示:

ls_output="$(ls)"

然后使用以下任何命令将该变量的值写入文件:

printf '%s\n' "$ls_output" > info.txt
cat <<< "$ls_output" > info.txt
echo "$ls_output" > info.txt

这种方法的一些注意事项:

  • Bash 变量不能包含空字节。如果命令的输出包含一个空字节,则该字节及其之后的所有内容都将被丢弃。
    • 不过,在 ls 的特定情况下,这应该不是问题,因为 ls 的输出绝不应该包含空字节。
  • $(...) 删除尾随换行符。上面通过在创建info.txt 时添加换行符来弥补这一点,但是如果命令输出以 multiple 换行符结尾,那么上面将有效地将它们折叠成一个换行符。
    • ls 的特定情况下,如果文件名以换行符结尾,则可能发生这种情况 — 非常不寻常,不太可能是故意的,但仍有可能。
  • 由于上面在创建info.txt 时添加了一个换行符,因此即使命令输出没有以换行符结尾,它也会在其中放置一个换行符。
    • ls 的特定情况下,这应该不是问题,因为ls 的输出应始终以换行符结尾。

如果您想避免上述问题,另一种方法是将您的命令输出保存到不同目录的临时文件中,然后将其移动到正确的位置;例如:

tmpfile="$(mktemp)"
ls > "$tmpfile"
mv -- "$tmpfile" info.txt

。 . .这显然有不同的警告(例如,它需要访问以写入不同的目录),但应该适用于大多数系统。

【讨论】:

    【解决方案3】:

    一种方法是从ls 输出中排除info.txt 文件。

    如果您可以将列表文件重命名为.info.txt,那么它很简单:

    ls >.info.txt
    

    ls 默认不列出名称以. 开头的文件。

    如果您无法重命名列表文件,但您拥有 GNU ls,那么您可以使用:

    ls --ignore=info.txt >info.txt
    

    如果做不到这一点,你可以使用:

    ls | grep -v '^info\.txt$' >info.txt
    

    上述所有选项的优点是您可以在创建列表文件后安全地运行它们。

    另一种通用方法是使用一个命令捕获ls 的输出,并使用第二个命令将其保存到列表文件中。正如其他人所指出的,临时文件和 shell 变量是捕获输出的两种特定方式。另一种方法是,如果您安装了 moreutils 软件包,则使用 sponge 实用程序:

    ls | sponge info.txt
    

    最后,请注意,如果 info.txt 包含普通的 ls 输出,您可能无法可靠地提取文件列表。请参阅ParsingLs - Greg's Wiki 了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-15
      • 2013-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-08
      • 2021-10-18
      • 1970-01-01
      相关资源
      最近更新 更多