【问题标题】:Using output piped from sed使用来自 sed 的输出
【发布时间】:2018-10-29 01:11:21
【问题描述】:

我有一个 sed 命令,它正在捕获带有 sometext 的单行。它正在捕获的文件中的行以换行结束。我正在尝试在管道中使用此变量,但是,当我尝试回显或将其与需要输入的其他命令一起使用时,结果为空白。前任: sed '1,1!d' somefile.txt | echo "$1",我知道变量本身不是空的,因为我可以将 echo "$1" 替换为 cat $1 并查看正确的打印输出。

edit - 我尝试通过管道连接到 tr -d 并删除换行符。我已经确认换行符消失了,但回声仍然显示为空白。猫不会。

edit 2 - 我将变量输入到 if 语句 ... | if [[ -z $1 ]]; then cat $1; fi 中,它遇到了 if,被确定为空,因此运行 cat,它将非空行打印到控制台。如果变量为空,为什么 cat 还在打印信息?

是什么导致了这种不一致,我该如何解决我的问题?最终目标是运行一个 sed 的输出,通过另一个来替换目标文件中的特定行。

sed '1,1!d' somefile.txt | sed '2,1s/.*/'$1'/' targetfile.txt

somefile.txt 的内容:

these
are
words

targetfile.txt 的内容:

The next line should say these
This line should say these
The previous line should say these

sed 后的 echo 输出:

<empty>

sed 后 cat 的输出:

these

第二个 sed 的输出,使用来自第一个的输入:

The next line should say these

the previous line should say these

【问题讨论】:

  • 创建一个可以测试的样本是什么意思?我已经完整地描述了我的过程。我在运行我自己的测试时从一个包含 3 行乱码的文件中取出一行。你真的需要我描述一个乱码测试文件的内容吗?我只是运行命令 sed'1,1!d' somefile.txt | echo "$1"sed'1,1!d' somefile.txt | sed '1,1s/.*/'$1'/' FileToChange.txt"sed'1,1!d' somefile.txt | cat $1 其中 somefile.txt 的内容是这些\n 是\n 单词\n (每个单词当然是它自己的行)如上所述,Cat 是只有一个打印非空行。
  • 我并不是说听起来粗鲁,但我刚才所说的一切都在我问的问题中。我不知道我应该如何在第一次 sed 之后给你输出,或者中间输出,因为我已经说过,在 cat 中不使用时它是空白的。你能更好地解释一下不清楚的地方吗?
  • @Erudaki 我们不需要您描述乱码测试文件的内容,我们需要您向我们展示测试内容文件,乱码或其他。措辞模棱两可——我们需要一个具体的minimal reproducible example,具有简洁、可测试的样本输入和执行的输出,以帮助证明您的问题,并且我们可以测试潜在的解决方案以查看它是否有效。另外,现在您向我们寻求帮助,以解决您认为解决问题的语法,而不是如何正确解决问题,即听起来像是 XY 问题。如果不清楚,请参阅How to Ask
  • @Erudaki 请选择您的样本数据并单击{} 编辑图标或按ctrl+k... 对于给定的somefile.txt,您不需要使用\n... 和targetfile.txt,您能否添加预期的输出?我仍然不清楚您的要求是什么(不确定您是否知道what $1 means
  • 带有示例输入数据的问题示例,预期输出格式正确 - stackoverflow.com/questions/46870285/…stackoverflow.com/questions/48920626/…

标签: unix awk sed


【解决方案1】:

您对参数和输入数据感到困惑。看看这个:

$ echo "$1"

$ echo "foo" | if [[ -z $1 ]]; then cat $1; fi
foo

我的 shell 的第一个参数 $1 是空的,所以 if [[ -z $1 ]] 成功。 cat $1 产生输出的原因是您在该语句中有一个基本的 shell 编程错误 - 您没有引用您的变量 $1。正确的语法不是cat $1,而是cat "$1"。看看区别:

$ echo "foo" | if [[ -z $1 ]]; then cat "$1"; fi
cat: '': No such file or directory

我们可以简化代码,让发生的事情更清楚:

$ echo "foo" | cat $1
foo

$ echo "foo" | cat "$1"
cat: '': No such file or directory

echo "foo" | cat $1 产生输出的原因是未引用的 $1 在调用 cat 之前被 shell 扩展为空,因此该语句等同于 echo "foo" | cat,因此 cat 只是复制来自管道到它的输出。

另一方面,echo "foo" | cat "$1" 会产生错误,因为 shell 在调用 cat 之前会将 "$1" 扩展为空字符串,因此它会要求 cat 打开一个名为 &lt;null&gt; 的文件,而该文件当然不存在,因此错误。

除非您有特定的理由不完全理解所有含义,否则请始终引用您的 shell 变量。如果您不确定这些含义是什么,请阅读 shell 手册页和/或 google。

写下你的另一部分代码:

sed '1,1!d' somefile.txt | echo "$1"

但是,与cat 不同,echo 既不会从管道读取输入,也不会从作为参数传递的文件名读取。 echo 的输入只是您提供的字符串参数列表,因此 echo "foo" | cat 将导致 cat 读取包含 foo 的输入流并将其输出,echo "foo" | echo 将不产生输出,因为 echo 不是设计的从管道读取输入,所以它只会打印一个空字符串,因为你没有给它任何参数。

尚不清楚您真正想要完成什么,但我认为您可能希望将targetfile.txt 的第二行替换为somefile.txt 的第一行。如果是这样,那就是:

awk '
    NR==FNR { if (NR==1) new=$0; next }
    FNR==2  { $0 = new }
    { print }
' somefile.txt targetfile.txt

不要尝试使用 sed 来执行此操作,否则您会发现自己在逃避/引用地狱,因为与 awk 不同,sed 不理解文字字符串,请参阅 Is it possible to escape regex metacharacters reliably with sed

【讨论】:

    【解决方案2】:

    您似乎想从file1 中提取第一行并用它来替换file2 中的第二行。

    目前,您使用第一个 sed 从第一个文件中提取该值,但将其发送到第二个 sed 上的 stdin,而不是作为参数 ($1)。

    您的描述令人困惑,因此我将其用作file1

    File 1 Line 1
    File 1 Line 2
    File 1 Line 3
    

    这是file2:

    File 2 Line 1
    File 2 Line 2
    File 2 Line 3
    

    有很多方法可以做到这一点。


    方法一

    # Extract line1 from file1
    extracted=$(sed '1!d' file1)
    # Replace line 2 in file2 with extracted value
    sed "2s/.*/$extracted/" file2
    

    不知道为什么我现在觉得自己像个牙医 :-)

    如果你想把它放在一行上,就像有些人喜欢做的那样:

    x=$(sed '1!d' file1) && sed "2s/.*/$x/" file2
    

    方法二

    这个有点棘手。它使用第一个sed 为第二个sed 编写脚本:

    sed  's/^/2s|.*|/;s/$/|/;q' file1 | sed -f /dev/stdin file2
    

    如果您单独查看第一个 sed,您会看到它正在为第二个生成脚本:

    sed  's/^/2s|.*|/;s/$/|/;q' file1
    2s|.*|File 1 Line 1|
    

    如果您查看第二个sed,您会看到它正在执行通过其标准输入传递的脚本:

    sed -f /dev/stdin ...
    

    方法3

    awk 更简单:

    awk 'FNR==NR{if(NR==1)saved=$0;next} FNR==2{$0=saved}1' file1 file2
    File 2 Line 1
    File 1 Line 1
    File 2 Line 3
    

    您需要注意的是,我将 2 个文件传递给 awk,而脚本中的 FNR==NR 意味着 awk 当前正在处理第一个文件,因为 FNR 是当前文件中的行号,并且NR 是迄今为止从所有文件中处理的awk 的总行数。因此,在处理第二个文件时,NR 比 FNR 大第一个文件中的行数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-14
      • 2017-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-03
      相关资源
      最近更新 更多