【问题标题】:As with the command: "echo '#!/bin/bash' |tee file", but with "echo '#!/bin/bash' | myscript file"与命令一样:“echo '#!/bin/bash' |tee 文件”,但使用“echo '#!/bin/bash' | myscript 文件”
【发布时间】:2016-01-01 04:14:00
【问题描述】:

“... | tee file”的作用是将标准输入(标准输入)转移到两个地方:标准输出(标准输出)和名为“文件”的路径/文件。据我判断,它实际上是这样做的:

    #!/bin/bash
    var=(cat)       # same as var=(cat /dev/stdin)
    echo -e "$var"
    for file in "$@"
    do
      echo -e "$var" > "${file}"
    done
    exit 0

所以我使用上面的代码来创建 tee1 看看我是否可以模仿 tee 的作用。但我的真正意图是编写一个附加到现有文件的修改版本,而不是从头开始重做它们。我称它为 tee2:

  #!/bin/bash
  var=(cat)       # same as var=(cat /dev/stdin)
  echo -e "$var"
  for file in "$@"
  do
    echo -e "$var" >> "${file}"
  done
  exit 0

这对我来说很有意义,但不是为了抨击。现在另一种方法是做这样的事情:

  echo -e "$var"
  for file in "$@"
  do
    echo -e "$var"| tee tmpfile
    cat tmpfile  >> "${file}"
  done
  rm tmpfile
  exit 0

这样做对我来说也很有意义:

  #!/bin/bash
  cp -rfp /dev/stdin tmpfile
  cat tmpfile
  for file in "$@"
  do
    cat tmpfile >> "${file}"
  done
  exit 0

或者这个:

  #!/bin/bash
  cat /dev/stdin
  for file in "$@"
  do
    cat /dev/stdin  >> "${file}"
  done
  exit 0

一些在线搜索建议使用 printf 代替 echo -e 以提高跨平台的一致性。其他人建议使用 cat 代替 read,但由于 stdin 是一种设备,它应该能够代替 catm 使用,如下所示:

    > tmpfile
    IFS=\n
    while read line
   do
     echo $line >> tmpfile
     echo $line
   done < /dev/stdin
   unset IFS

然后是for循环。但我无法让它发挥作用。如何使用 bash 做到这一点?

【问题讨论】:

  • 您正在使用数组赋值 var=(cat) 而不是命令替换 var=$(cat)。这肯定是把事情往错误的方向发展。当然,“真正的”tee 在生成数据时读取和写入文件,而不是等到其标准输入上的 EOF 后再写入任何输出,但这主要是技术性问题。

标签: linux bash shell cat


【解决方案1】:

但我的真正意图是编写一个修改后的版本,附加到现有文件,而不是从头开始重做。

tee 实用程序指定支持-a 选项,意思是“将输出附加到文件”。 [spec]

(而且我不知道在这方面有任何偏离规范的tee 实现。)


编辑添加:如果您的问题真的是“我尝试过的所有不同的事情有什么问题”,那么对于单个 Stack Overflow 问题来说,这可能过于宽泛。但这里有一个简短的列表:

  • var=(cat) 表示“将数组变量var 设置为包含单个元素,即字符串cat。”
    • 请注意,这绝不涉及cat 程序。
    • 您可能指的是var=$(cat),意思是“运行命令cat,捕获其标准输出。丢弃任何空字节,并丢弃任何尾随的换行符序列。将结果保存在常规变量var 中。”
      • 请注意,即使是这个版本也不能忠实地实现tee,因为tee 确实 丢弃空字节和尾随换行符。此外,tee 在输入可用时转发输入,而var=$(cat) 必须等到输入完成。 (如果标准输入来自终端 - 在这种情况下,用户希望看到他们的输入回显 - 或者来自可能试图与用户通信的程序 - 在这种情况下,您会得到一个问题,这是一个问题死锁。)
  • echo -e "$var" 强调处理转义序列,如 \t。 (这就是-e 的意思。)这不是你想要的。此外,它附加了一个额外的换行符,如果您设法正确设置了$var,这不是您想要的。 (如果您没有设法正确设置 $var,那么这可能有助于弥补这一点,但它并不能真正解决问题。)
    • 如实打印var的内容,你应该写printf %s "$var"
  • 我不明白你为什么改用| tee tmpfile 方法。据我所知,它并没有改进任何东西,并且它引入了一个错误,即现在如果您要复制到 n 个文件,那么您还将编写 n 个副本到标准输出。 (不过,您在以后的版本中修复了该错误。)
  • 直接写入文件而不是先保存到变量的版本在忠实地复制标准输入的内容方面是一个巨大的改进。但是他们仍然存在等待输入完成的问题。
  • cat /dev/stdin 多次(每个目的地一次)的版本将不起作用,因为标准输入没有“倒带”。东西吃完了,就没了。 (当您考虑到标准输入经常在程序之间传递时,这是有道理的——例如,您的cat-s 是从您的 Bash 脚本继承它,而您的 Bash 脚本可能是从终端继承它。如果会发生某种自动倒带,它如何决定回退多远?)(注意:如果标准输入来自常规文件,则可以显式沿着它向后搜索,从而“取消使用”已经使用的输入。但这不会自动发生,而且无论如何,当标准输入来自终端、管道等时,这是不可能的)

【讨论】:

  • 感谢您提供的信息!让我的生活轻松一点。但热到这一步,我正在向前推进。处理 stdin、stfout 和 stderr,我现在可以继续编写自己的过滤器和实用程序。就像一个“定位
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多