在模式和bash中相同模式的下一次出现之间添加带文本的行

时间:2011-02-06 21:15:37

标签: bash sed awk

我正在编写一个bash脚本来修改一个如下所示的文件:

--- usr1 ---
data data data data
data data data data
data data data data
--- usr2 ---
data data data data
data data data data
--- usr3 ---
data data data data
--- endline ---

一个问题是:如何在最后一个用户数据行之后添加下一个用户行--- usrn ---? 第二个是:如何删除特定的用户数据行(数据行和--- userx ---),即我想删除usr2及其所有数据集。

它必须适用于bash 2.05 :)我认为它会使用awk或sed,但我不确定。
这里有一点编辑:实际上用户名没有编号。我们不知道用户会想出什么。我们只知道名称将在---模式

3 个答案:

答案 0 :(得分:1)

给出变量中的用户名:

username="kasper"

删除用户部分:

sed "/$username/{:a;N;/\n--- [^[:blank:]]* ---\$/{s/.*\n//;b};ba}" inputfile

或某些版本的sed已修改):

sed -e "/$username/{" -e ':a' -e 'N' -e '/\n--- [^[:blank:]]* ---$/{s/.*\n//' -e 'b' -e '}' -e 'ba' -e '}' inputfile

编辑:可能的变体以容纳前导和尾随空格:

sed -e "/$username/{" -e ':a' -e 'N' -e '/\n[[:blank:]]*---[[:blank:]]*[^[:blank:]]*[[:blank:]]*---[[:blank:]]*$/{s/.*\n//' -e 'b' -e '}' -e 'ba' -e '}' inputfile

添加下一个用户部分:

sed "s/--- end/--- $username ---\ndata data data data\ndata data data data\n&/"

sed "/--- end/i--- $username ---\ndatadata data data\ndata data data data\n"

如果您的sed版本支持就地更改,则可以执行以下操作:

sed -i ...

否则,您将不得不使用临时文件:

sed ... inputfile > tmpfile && mv tmpfile inputfile

最好使用mktemptempfile等实用程序来创建临时文件并使用提供的名称。

答案 1 :(得分:0)

普通shell可以处理这个

更新了答案以包含第二项要求 ...

#!/bin/sh

NEWUSER='John Doe'
NEWUSERDATA='how now brown cow'
REMOVEUSER='usr2'

state=COPY
while read x; do
  case "$state/$x" in
    *"/--- endline ---")
      echo --- $NEWUSER ---
      echo "$NEWUSERDATA"
      state=COPY
      ;;
    COPY/*)
      if [ "$x" == "--- $REMOVEUSER ---" ]; then
        state=REMOVE
      fi
      ;;
    REMOVE/---*)
      state=COPY
      ;;
  esac
  if [ $state != REMOVE ]; then
    echo "$x"
  fi
done

用法类似于:sh newuser.sh < usertable.txt > newusertable.txt

顺便说一句,还有一种编写shell脚本的替代方式,我称之为“gnu configure”格式。在“替代风格”中,主循环将是:

while read x; do
  case "$state/$x" in
    *"/--- endline ---")
      echo --- $NEWUSER ---
      echo "$NEWUSERDATA"
      state=COPY;;
    COPY/*)
      [ "$x" == "--- $REMOVEUSER ---" ] && state=REMOVE;;
    REMOVE/---*)
      state=COPY;;
  esac
  [ $state != REMOVE ] && echo "$x"
done

答案 2 :(得分:0)

第二部分的awk解决方案:

awk -v del="usr2" 'match($0,/^--- (.*) ---$/,a) {p = (a[1] != del)} p'

如果头部与要删除的用户匹配,则会关闭p标志,否则会打印每一行。