Bash - 从模式替换为另一种模式以及介于两者之间的所有模式

时间:2014-06-08 13:37:42

标签: linux bash awk sed

我有一个这样的文本文件:

  
      
  1. 目录Test / Movie1
  2.   
  3. Quote1 -rw-rw-r-- 63 1 1
  4.   
  5. @
  6.   
  7. 目录Test / Movie2
  8.   
  9. Quote2 -rw-rw-r-- 24 2 1
  10.   
  11. @
  12.   
  13. ...(文件继续)
  14.   

我想要这个输出:

  
      
  1. 目录Test / Movie1
  2.   
  3. Quote1 -rw-rw-r-- 63 1 1
  4.   
  5. @
  6.   
  7.   
  8.   
  9.   
  10. ...
  11.   

我已经尝试过这个命令:

sed '0,/'"Test\/Quote1"'/d;/@/,$d' header.txt

但它并没有给我所需的输出。 谢谢你的帮助

修改

我试图重新创建一些shell命令来格式化文件" header.txt" 如果我输入

rm Test/Movie2

我的脚本是这样的:

while read -a line
do
 if [[ "${line[0]}" == "rm" ]]; then
  sed -i "/${line[1]}/"'s/.*//' header.txt #replacing Test/Movie2 by blank line

done

现在,我想用空行替换"目录Test / Movie2"直到下一个分隔符" @"

4 个答案:

答案 0 :(得分:1)

根据您的sed表达式,我认为您想要使用的是:

sed '/Test\/Movie2/,/@/d;' header.txt

换句话说:从模式Test/Movie2删除到跟随@(包括)。它提供了你想要的输出。

编辑:上面的命令将完全删除模式之间的行。

这是另一个命令行,它将用空行替换它们:

sed '/Test\/Movie2/,/@/g;' header.txt

(我们不会使用d命令删除模式并且不打印任何内容,而是加载并打印sed保留空间的内容,这是空的。)

答案 1 :(得分:0)

这只会在首次找到@之后打印空行(它给出了我在帖子中显示的内容,但我猜它不是你想要的)

awk 'f {$0=""} /@/ {f=1} 1' file
directory Test/Movie1
Quote1 -rw-rw-r-- 63 1 1
@



.

.只是为了让这个页面显示空白行。

答案 2 :(得分:0)

您可以尝试以下方式:

#!/bin/bash

IN_FILE="test.txt"

remove(){
    [[ $1 ]] || error
    awk -v dir="$1" 'BEGIN{np=0; w=0}
    ($2 == dir){np=1; w=0}
    (np == 1 && $0 == "@"){np=0; w=1}
    {if(np == 0 && w == 0){print $0} else {print ""; w=0}}' "$IN_FILE"
}

bye(){
    echo "Bye..."
    exit 0
}

error(){
    echo "Invalid command" >&2
}

while true; do
    read -rp "> " command
    set -- "$command"
    case "$1" in
        rm) remove "$2" ;;
        exit) bye ;;
        *) error ;;
    esac
done

示范:

$ cat test.txt
directory Test/Movie1
Quote1 -rw-rw-r-- 63 1 1
@
directory Test/Movie2
Quote2 -rw-rw-r-- 24 2 1
@
$ ./test.sh
> rm something
directory Test/Movie1
Quote1 -rw-rw-r-- 63 1 1
@
directory Test/Movie2
Quote2 -rw-rw-r-- 24 2 1
@
> rm Test/Movie1



directory Test/Movie2
Quote2 -rw-rw-r-- 24 2 1
@
> rm Test/Movie2
directory Test/Movie1
Quote1 -rw-rw-r-- 63 1 1
@



> exit
Bye...

答案 3 :(得分:0)

如果我理解正确,那么每一行以"目录"开头。以" @"结束表示一个记录,并且您希望能够通过指定"目录"之后的内容来从文件中删除记录(一组行)。在那条线上。

如果环境变量名为" movie"包含您要删除的内容,这将在您指定的影片记录中输出相同的列表:

movie="Test/Movie2"
sed -r ":a;N;\$!ba;s~(\n?)directory ${movie}\n[^@]*@\n?~\1~" < header.txt

如果您想要修改文件,可以使用&#34; -i&#34;:

movie="Test/Movie2"
sed -r -i ":a;N;\$!ba;s~(\n?)directory ${movie}[^@]*@\n?~\1~" header.txt

我使用了波浪号(〜)而不是通常的正斜杠(/)来分隔子组件,以防止电影记录中的任何斜线(例如&#34; Test / Movie2&#34;)混淆sed 。此外,之前的东西是&#34; s~&#34;使sed将整个文件视为一行,以允许查找和替换换行符。

请注意,这只适用于GNU sed,这在Linux中很常见。如果您使用的是OS X或BSD,则sed更受限制,因此您可以安装GNU sed,或者使用它:

movie="Test/Movie2"
tr "\n" "\177" < header.txt \
| sed -E "s~("$'\x7F'"?)directory ${movie}"$'\x7F'"[^@]*@"$'\x7F'"?~\1~" \
| tr "\177" "\n"