【问题标题】:Insert multiple lines in file before specified pattern在指定模式之前在文件中插入多行
【发布时间】:2019-10-22 18:15:30
【问题描述】:

如果内容有新行并且此内容由函数生成,则无法在匹配行之前添加行

另一个看起来不错的替代方案 (Insert multiple lines into a file after specified pattern using shell script) 但它只附加了“AFTER”。我需要“之前”

然后将xml内容放入add.txt

sed '/4/r add.txt' $FILE

#/bin/sh

FILE=/tmp/sample.txt
form_xml_string()
{
  echo "<number value=\"11942\">"
  echo "  <string-attribute>\"hello\"</string-attribute>"
  echo "</number>"
}

create_file()
{
  if [ -e $FILE ]
  then
          echo "Removing file $FILE"
          rm $FILE
  fi

  i=1
  while [ $i -le 5 ]
  do
          echo "$i" >> $FILE
          i=$(( i+1 ))
   done
}

create_file
cat $FILE

# file sample.txt has numbers 1 to 5 in each line
# Now append the content from form_xml_string to line before 4
# command I tried
CONTENT=`form_xml_string`
echo "CONTENT is $CONTENT"
sed -i "/4/i $CONTENT" $FILE
cat $FILE

预期输出:

1
2
3
<number value="11942">
  <string-attribute>"hello"</string-attribute>
</number>
4
5

实际输出(或错误): sed:-e 表达式 #1,字符 31:未知命令:`

【问题讨论】:

  • 可能是我遗漏了一些东西,但sed -i "/4/i $CONTENT" $FILE 已经做了你想做的事情(在给定的匹配模式之前插入行)......那么这里真正的问题是什么?跨度>
  • 忘记添加“实际输出”:这是:sed: -e expression #1, char 31: unknown command: `

标签: bash shell sed


【解决方案1】:

您收到该错误是正常的,您的文本语法与您的 sed 命令不兼容,请允许我详细说明:

  • 首先,您的文本中有很多/s,而/sed 中的分隔符,这会混淆命令,这就是您收到该错误的原因。因此,您应该转义您正在使用的文本中的所有/,将它们替换为\\/(额外的\ 将由shell 解释)。

  • 其次,在sed的人中,我们可以看到关于/i的这条小线:

插入文本,每个嵌入的换行符前面都有一个反斜杠

这意味着您还需要在每个换行符之前添加\,在您的示例中,这意味着在每个echo 的末尾添加\\

编辑:

感谢Toby Speight 的评论,我注意到我完全忘记了更改sed 的分隔符的可能性,这可以让您的生活更轻松,因为您不必添加\\在文本中的每个 / 之前。为此,您只需将这一行 sed -i "/4/i $CONTENT" $FILE 更改为例如 sed -i "\\_4_i $CONTENT" $FILE

引入这些更改后,您的脚本将变为以下内容:

#! /bin/sh
FILE=/tmp/sample.txt
form_xml_string()
{
  echo "<number value=\"11942\">\\"
  echo "  <string-attribute>\"hello\"</string-attribute>\\"
  echo "</number>"
}

create_file()
{
  if [ -e $FILE ]
  then
          echo "Removing file $FILE"
          rm $FILE
  fi

  i=1
  while [ $i -le 5 ]
  do
          echo "$i" >> $FILE
          i=$(( i+1 ))
   done
}

create_file
cat $FILE

# file sample.txt has numbers 1 to 5 in each line
# Now append the content from form_xml_string to line before 4
# command I tried
CONTENT=`form_xml_string`
echo "CONTENT is $CONTENT"
sed -i "\\_4_i $CONTENT" $FILE
cat $FILE

【讨论】:

  • 在 sed 程序中使用不同的分隔符可能更简单。
  • 谢谢托比·斯佩特和史蒂夫!
  • 顺便说一句,忘了问一个问题,你怎么知道在默认分隔符更改时使用“_”作为分隔符。其他符号会起作用吗?
  • 是的,大多数符号都可以,您可以使用,:| 甚至#,我选择了_,因为这是我的个人喜好。跨度>
【解决方案2】:

使用e 代替r

来自关于e 命令的 Sed 手册:

请注意,与 r 命令不同,该命令的输出将立即打印; r 命令将输出延迟到当前循环的末尾。

r 命令的延迟是问题所在,在它之后你不能输出任何东西。

e 命令示例:

seq 0 9 | sed -e '/4/{
  h
  e cat add.xml
  g
}'

h 将匹配行复制到保持空间,g 将其复制回模式空间。这样它就会出现在输出中的“add.xml”之后。

【讨论】:

  • 我也喜欢这种方法,但由于上述方法(更改分隔符)允许我使用函数并避免文件,我更喜欢这种方法。感谢您推荐这个。
  • 如果将该 cat 行写为“e cat $ADD_FILE”,这种方法似乎不起作用
  • 如果我将 sed -e ' 更改为 sed -e " (从单引号变为双引号),它可以工作!:)
猜你喜欢
  • 1970-01-01
  • 2016-06-16
  • 1970-01-01
  • 2014-04-25
  • 2015-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多