【问题标题】:sed from pattern till end of file inside a for loopsed 从模式到 for 循环内的文件末尾
【发布时间】:2015-03-25 12:05:39
【问题描述】:

我正在编写一个 bash 脚本,它允许我从文件中获取一定数量的文本,并在此之前为文件列表添加一些其他文本。

directory=$(pwd)

    for f in *test.txt
    do


        filename=$(basename $f .txt)

        printf "%%sum=4 \n"> input.temp
        printf "file=$directory"/"$filename".txt" \n">> input.temp

        printf "some commands \n">> input.temp

        printf "\n" >> input.temp
        printf "description \n">> input.temp

        sed -n "/0 1/,$p" "$f" >> input.temp;


mv input.temp $filename.temp
done

我在 for 循环中的 sed 命令有问题。我环顾四周,人们建议我添加双引号,但无济于事。我认为这可能是$ p。 我希望这足够清楚。如果不是,我会尝试解释得更好。

sed -n "/0 1/,$p" "$f" >> input.temp; 不起作用

sed -n '/0 1/,$p' "$f" >> input.temp; 不起作用

sed -n "/0 1/,\$p" "$f" >> input.temp; 不起作用

仅供参考,我不想找到其他可行的方法。我想修复这个确切的输入。我敢肯定,我听起来像个混蛋。

示例输入

%sum=8
file=otherpath/filename.txt
some other commands

another description

0 1

                       0.36920852   -0.56246512    
                       0.77541848    0.05756533    
                       2.05409026    0.62333039    
                       2.92655258    0.56906375    
                       2.52034254   -0.05096652    
                       1.24167014   -0.61673008    
                      -0.60708600   -0.99443872    
                       0.10927459    0.09899803    
                       3.90284624    1.00103940    
                       3.18648588   -0.09239788    
                       0.93151968   -1.09013674    
                       2.50047427    1.30468389    
                       2.19361322    2.54108378   
                       3.18742399    0.34152442   
                       3.38679424    1.11276220   
                       1.56936488    3.27250306    
                       1.81754180    4.19564055    

     1 2 1.5 6
     2 3 1.5 
     3 4 
     4 5 1.5
     5 6 1.5 
     6 11 1.0
     7
     8
     9
     10
     11
     12
     13 16
     14 
     15
     16 17
     17

我想要的输出基本上是这个从“0 1”到结尾的文件,前面是我放在 printf 中的东西。

更新:如果您有兴趣,triplee 和 Ed Morton 提供的两个脚本运行良好。我的脚本中的问题是我从 sed 行中省略了 -i 选项(用于就地)。

sed -n "/0 1/,$p" "$f" >> input.temp

应该替换为

sed -ni '/0 1/,$p' "$f"

【问题讨论】:

  • 我认为您需要单引号,以防止 $p 被视为 shell 变量而不是 sed 代码:sed -n '/0 1/,$p' "$f" >> input.temp。不过,要知道你到底想在那里做什么有点困难。
  • 这里的大括号有点古怪。
  • 您知道每次连续迭代都会覆盖 inputout.temp2,对吗?我猜这只是一个试验台,但仅供参考
  • 我修复了 % 符号问题。 mv 命令应该将临时文件移动到原始文件中以替换它。带简单引号的 sed 不起作用。
  • 是的。也许你误解了什么。解决方法是仅在 sed 脚本周围使用单引号; sed -n '/0 1/,$p' "$f" 所以文件名参数仍应使用双引号。

标签: bash for-loop sed


【解决方案1】:

我看到你更新了你的问题并在你的 cmets 中提供了一些额外的信息,所以试试这个,使用 GNU awk 4.* for -i inplace

awk -i inplace -v directory="$(pwd)" '
FNR==1 {
    print "%%sum=4 "
    print "file=" directory "/" FILENAME
    print "some commands "
    print ""
    print "description "
    found = 0
}
/0 1/ { found = 1 }
found
' *text.txt

如果您没有 GNU awk,那么技术上正确的方法是使用 xargs,但在文件操作(移动)部分使用 shell 循环会更简单:

for file in *test.txt
do
    awk -v directory="$(pwd)" '
    FNR==1 {
        print "%%sum=4 "
        print "file=" directory "/" FILENAME
        print "some commands "
        print ""
        print "description "
        found = 0
    }
    /0 1/ { found = 1 }
    found
    ' "$file" > tmp && mv tmp "$file"
done

【讨论】:

  • 感谢您的回答。不幸的是,我正在使用的系统有 awk 3.1.7。
  • 您应该升级,因为您缺少很多非常有用的功能。不过,我现在为我的答案添加了一个非笨拙的解决方案。
  • 好吧,猜猜你坚持下去了。需要牢记的一些关键事项 - UNIX shell 是一个环境,可以从中调用 UNIX 工具,并使用一种语言来对这些调用进行排序。用于对单个行进行简单替换的 UNIX 工具是 sed。用于通用文本操作的 UNIX 工具是 awk。因此,通常当您需要在 UNIX 中操作文本时,您会从 shell 调用 awk。就是这样。
【解决方案2】:

就像其他人已经评论过的那样,您基本上只需要使用单引号而不是双引号,因为在sed 执行之前,双引号中的$p 被shell 替换为shell 变量p 的值(实际上,可能是一个空字符串)。

但是,您可能还想在sed 中进行调查。然后,您可能会改用双引号(因为您确实想要替换其他变量),而是使用反斜杠转义 $p 中的美元符号以保护它免受 shell 的影响。

directory=$(pwd)   # just do this once before the loop; the value doesn't change
for f in *text.txt; do
    # no braces
    filename=$(basename "$f" .txt)
    sed -n "1i\\
%sum=4\\
file=$directory/$filename.txt\\
some commands\\
\\
description
        /0 1/,\$p" "$f" >inputout.temp2  # no pointless separate temp file
done

在实践中,我想您希望输出文件在每次迭代中都不同(也许是 "$filename.temp"?),但您对此做什么显然取决于您。就像现在一样,该文件将包含上次迭代的输出。

【讨论】:

  • 它在生成的输出的第一行插入所需的文本,而不是摆弄大量的printf 调用。
  • 好的。所以这行得通。但是,你能帮我理解为什么我的 sed 没有(不是单引号或双引号)
  • sed -n '/0 1/,$p' "$f" >> input.temp 在 for 循环中不起作用
  • 使用双引号,shell 将$p 扩展为一个空字符串,因此当sed 看到/0 1/, 而没有任何操作时会出现语法错误。将脚本放在单引号中应该可以工作,或者保留双引号并使用反斜杠,就像我在答案中所做的那样。
  • 在这里工作:ideone.com/YZgo6J - 我必须做一个小改动,我已将其合并到上面的答案中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
  • 2015-06-06
  • 1970-01-01
  • 2014-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多