开发者问题收集

在文件中指定模式之前插入多行

2019-06-07
1428

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

另一个看起来不错的替代方案( 使用 shell 脚本在指定模式后将多行插入文件中 )但它只附加了“AFTER”。我需要“BEFORE”

然后将 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:未知命令:`<'

3个回答

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

  • 首先,您的文本中有很多 / ,而 /sed 中的分隔符,这会混淆命令,这就是您出现该错误的原因。因此,您应该将文本中的所有 / 都转义,方法是将其替换为 \\/ (额外的 \ 将由 shell 解释)。

  • 其次,在 sed 的 man 中,我们可以看到关于 /i 的这一小行:

Insert text, which has each embedded newline preceded by a backslash

这意味着您还需要在每个换行符前添加一个 \ ,在您的示例中,这意味着在每个 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
Ghassen Manai
2019-06-07

使用 e 代替 r

来自 Sed 手册中有关 e 命令的内容:

Note that, unlike the r command, the output of the command will be printed immediately; the r command instead delays the output to the end of the current cycle.

r 命令的延迟是问题所在,您无法在它之后输出任何内容。

e 命令的示例:

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

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

ceving
2019-06-07

假设您只想在第一个 之前插入 /tmp/snippet 的内容。

awk '
    /}/ && !done {          # Search for the first "}" and check if insertion is not done
        while ((getline line < "/tmp/snippet") > 0) {
            print line      # Print each line from the snippet file
        }
        print "}"           # Print the original "}" after the snippet
        done=1              # Set done to 1 to avoid further insertions
        next                # Skip the original line containing "}"
    }
    { print }               # Print all other lines as is
' /path/to/file > /tmp/tmp2 && mv /tmp/tmp2 /path/to/file

必须有 /tmp/tmp2 很丑陋,但它是必需的

ᴍᴇʜᴏᴠ
2024-04-26