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

发布于 2024-10-16 06:51:13 字数 466 浏览 2 评论 0原文

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

--- usr1 ---
数据数据数据数据数据
数据数据数据数据数据
数据数据数据数据数据
--- usr2 ---
数据数据数据数据数据
数据数据数据数据数据
--- usr3 ---
数据数据数据数据
--- endline ---

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

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

I am writing a bash script that modifies a file that looks like this:

--- 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 ---

One question is: How to add next user line --- usrn --- after last user data lines?
Second one is: How to delete specific user data lines (data lines and --- userx ---) i.e. I would like to delete usr2 with all his data set.

It must work on bash 2.05 :) and I think it will use awk or sed, but I'm not sure.
A little edit here: In fact usernames are not numbered. We don't know what users will come up with. We only know that the name will be inside --- pattern

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

握住你手 2024-10-23 06:51:13

给定变量中的用户名:

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 等实用程序用于创建临时文件并使用提供的名称。

Given a username in a variable:

username="kasper"

Delete a user section:

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

or for some versions of sed (edited):

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

Edit: a possible variation to accommodate leading and trailing whitespace:

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

Add the next user section:

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

or

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

If your version of sed supports in-place changes, you can do:

sed -i ...

Otherwise, you'll have to use a temporary file:

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

It's best to use a utility like mktemp or tempfile to create a temporary file and use the name provided.

北笙凉宸 2024-10-23 06:51:13

第二部分的 awk 解决方案:

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

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

An awk solution for the 2nd part:

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

This turns the p flag off if the head matched the user to delete, otherwise it prints every line.

残疾 2024-10-23 06:51:13

普通 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 sh newuser.sh 用户表.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

Plain shell can handle this

Updated answer to include the second requirement...

#!/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

Usage is something like: sh newuser.sh < usertable.txt > newusertable.txt

By the way, there is an alternative style of writing shell scripts which I might call "gnu configure" format. In "alternative style" the main loop would be:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文