AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 20649
Accepted
Peter.O
Peter.O
Asked: 2011-01-09 11:11:08 +0800 CST2011-01-09 11:11:08 +0800 CST 2011-01-09 11:11:08 +0800 CST

是否有一个命令行实用程序应用程序可以在文本文件中找到特定的行块并替换它?

  • 772

更新(见问题结尾)

我见过的文本“搜索和替换”实用程序似乎只能逐行搜索......

是否有一个命令行工具可以定位一个行块(在文本文件中),并将其替换为另一个行块。?

例如:测试文件文件是否包含以下exact group行:

'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,  
And the mome raths outgrabe. 

'Beware the Jabberwock, my son!
The jaws that bite, the claws that catch!
Beware the Jubjub bird, and shun
The frumious Bandersnatch!'

我想要这个,这样我就可以替换文件中的多行文本并且知道我没有覆盖错误的行。

我永远不会取代“The Jabberwocky”(刘易斯卡罗尔),但它是一个新颖的例子:)

更新:
..(子更新)我以下关于不使用 sed原因的评论仅适用于以下情况;不要将任何工具推得太远超出其设计意图(我经常使用 sed,并认为它非常宝贵。)

我刚刚发现了一个关于sed以及何时不使用它的有趣网页。
因此,由于所有sed答案,我将发布链接.. 它是sourceforge 上 sed 常见问题解答的一部分

另外,我很确定有某种方法diff可以完成定位文本块的工作(一旦找到,替换就很直接了;使用headand tail)......'diff'转储所有必要的数据,但我还没有弄清楚如何过滤它,......(我还在努力)

command-line
  • 5 5 个回答
  • 2441 Views

5 个回答

  • Voted
  1. Best Answer
    loevborg
    2011-01-10T09:57:32+08:002011-01-10T09:57:32+08:00

    这个简单的 python 脚本应该完成任务:

    
    #!/usr/bin/env python
    
    # Syntax: multiline-replace.py input.txt search.txt replacement.txt
    
    import sys
    
    inp = open(sys.argv[1]).read()
    needle = open(sys.argv[2]).read()
    replacement = open(sys.argv[3]).read()
    
    sys.stdout.write(inp.replace(needle,replacement))
    

    像大多数其他解决方案一样,它的缺点是整个文件一次被吞入内存。但是,对于小文本文件,它应该工作得很好。

    • 7
  2. Gilles 'SO- stop being evil'
    2011-01-09T12:03:26+08:002011-01-09T12:03:26+08:00

    方法1:暂时将换行符更改为其他内容

    以下代码段用管道交换换行符,执行替换,并将分隔符交换回来。如果它看到的线路非常长,该实用程序可能会阻塞。您可以选择任何要交换的字符,只要它不在您的搜索字符串中。

    <old.txt tr '\n' '|' |
    sed 's/\(|\|^\)'\''Twas … toves|Did … Bandersnatch!'\''|/new line 1|new line 2|/g' |
    tr '|' '\n' >new.txt
    

    方法 2:更改实用程序的记录分隔符

    awk 和 perl 支持设置两个或多个空行作为记录分隔符。使用 awk,通过-vRS=(空RS变量)。使用 Perl,通过-000(“段落模式”)或设置$,="". 这在这里没有帮助,因为您有一个多段搜索字符串。

    awk 和 perl 还支持将任何字符串设置为记录分隔符。将RS或设置$,为不在搜索字符串中的任何字符串。

    <old.txt perl -pe '
        BEGIN {$, = "|"}
        s/^'\''Twas … toves\nDid … Bandersnatch!'\''$/new line 1\nnew line 2/mg
    ' >new.txt
    

    方法 3:处理整个文件

    一些实用程序很容易让您将整个文件读入内存并对其进行处理。

    <old.txt perl -0777 -pe '
        s/^'\''Twas … toves\nDid … Bandersnatch!'\''$/new line 1\nnew line 2/mg
    ' >new.txt
    

    方法四:程序

    逐行阅读。从一个空缓冲区开始。如果您看到“'Twas”行并且缓冲区为空,请将其放入缓冲区中。如果您看到“Did gyre”并且缓冲区中有一行,则将当前行附加到缓冲区,依此类推。如果您刚刚添加了“Bandersnatch line”,则输出替换文本。如果当前行没有进入缓冲区,则打印缓冲区内容,打印当前行并清空缓冲区。

    psusi展示了一个 sed 实现。在 sed 中,缓冲区的概念是内置的;它被称为保持空间。在 awk 或 perl 中,您只需使用一个变量(可能是两个,一个用于缓冲区内容,一个用于行数)。

    • 3
  3. psusi
    2011-01-09T11:42:06+08:002011-01-09T11:42:06+08:00

    我确信必须有一种方法可以用 sed 做到这一点。经过一番谷歌搜索后,我发现了这个:

    http://austinmatzko.com/2008/04/26/sed-multi-line-search-and-replace/

    基于此,我最终写了:

    sed -n '1h;1!H;${;g;s/foo\nbar/jar\nhead/g;p;}' < x

    哪个正确地取了 x 的内容:

    富吧

    并吐出:

    罐头

    • 2
  4. loevborg
    2011-01-10T04:40:00+08:002011-01-10T04:40:00+08:00

    就算你不喜欢灰白色sed的perl,你也可能会喜欢上灰色的awk。这个答案似乎是您正在寻找的。我在这里复制它。假设您有三个文件并想needle用replacementin替换haystack:

    
    awk ' BEGIN { RS="" }
          FILENAME==ARGV[1] { s=$0 }
          FILENAME==ARGV[2] { r=$0 }
          FILENAME==ARGV[3] { sub(s,r) ; print }
        ' needle replacement haystack > output
    

    这不涉及正则表达式并支持换行符。它似乎适用于相当大的文件。它确实涉及将整个文件放入内存中,因此它不适用于任意大小的文件。如果您希望它更优雅,可以将整个 shebang 包含在 bash 脚本中,或者将其转换为awk脚本。

    • 2
  5. Peter.O
    2011-01-10T06:05:08+08:002011-01-10T06:05:08+08:00

    更新:loevborg 的 python 脚本无疑是最简单和最好的解决方案(毫无疑问),我对此非常满意,但我想指出我提出的 bash 脚本(在问题的结尾)远没有看起来那么复杂..我删除了我用来测试它的所有调试渣滓..这里再次没有负担(对于访问此页面的任何人)..它基本上是sed一个单线,与十六进制转换前后:

    F=("$haystack"  "$needle"  "$replacement")
    for f in "${F[@]}" ; do cat "$f" | hexdump -v -e '1/1 "%02x"' > "$f.hex" ; done
    sed -i "s/$(cat "${F[1])}.hex")/$(cat "${F[2])}.hex")/p" "${F[0])}.hex"
    cat "${F[0])}.hex" | xxd -r -p > "${F[0])}"
    # delete the temp *.hex files.
    

    只是为了把我的帽子扔进戒指,我想出了一个'sed'解决方案,它不会遇到特殊正则表达式字符的任何问题,因为它甚至没有使用一个!..相反,它适用于文件的Hexdumped版本...

    我认为它太“头重脚轻”了,但它可以工作,并且显然不受任何大小限制的限制。GNU sed 具有无限的模式缓冲区大小,这就是 Hexdumped 搜索行块结束的地方。所以在这方面没问题...

    我仍在寻找diff解决方案,因为它在空白方面会更加灵活(我希望;更快)……但在那之前……这是著名的 Sed 先生。:)

    该脚本完全按原样运行,并且经过合理评论......
    它看起来更大;我只有7行基本代码。
    对于半现实的测试,它从古腾堡计划 ( Project Gutenberg ) (363.1 KB) 下载“爱丽丝透过镜子”一书......并用自己的行反转版本替换原来的 Jabberwocky 诗......(有趣的是,它并不多不同的向后阅读:)

    PS。我刚刚意识到这种方法的一个弱点是如果您的原始使用 \r\n (0xODOA) 作为换行符,并且您的“要匹配的文本”保存为 \n (0x0A).. 那么这个匹配过程在水......('diff'没有这样的问题)......


    # In a text file, replace one block of lines with another block
    #
    # Keeping with the 'Jabberwocky' theme, 
    #  and using 'sed' with 'hexdump', so 
    #  there is no possible *special* char clash.
    # 
    # The current setup will replace only the first instance.
    #   Using sed's 'g' command, it cah change all instances. 
    #
    
      lookinglass="$HOME/Through the Looking-Glass by Lewis Carroll"
      jabberwocky="$lookinglass (jabberwocky)"
      ykcowrebbaj="$lookinglass (ykcowrebbaj)"
    
      ##### This section if FOR TEST PREPARATION ONLY
            fromURL="http://www.gutenberg.org/ebooks/12.txt.utf8"
            wget $fromURL -O "$lookinglass"
            if (($?==0))
            then  echo "Download OK"
            else  exit 1
            fi
            # Make a backup of the original (while testing)
            cp "$lookinglass" "$lookinglass(fromURL)"
            #
            # Extact the poem and write it to a file. (It runs from line 322-359)
            sed -n 322,359p "$lookinglass" > "$jabberwocky"
            cat "$jabberwocky"; read -p "This is the original.. (press Enter to continue)"
            #
            # Make a file containing a replacement block of lines
            tac "$jabberwocky" > "$ykcowrebbaj"
            cat "$ykcowrebbaj"; read -p "This is the REPLACEMENT.. (press Enter to continue)"
      ##### End TEST PREPARATION
    
    # The main process
    #
    # Make 'hexdump' versions of the 3 files... source, expected, replacement 
      cat "$lookinglass" | hexdump -v -e '1/1 "%02x"' > "$lookinglass.xdig"
      cat "$jabberwocky" | hexdump -v -e '1/1 "%02x"' > "$jabberwocky.xdig"
      cat "$ykcowrebbaj" | hexdump -v -e '1/1 "%02x"' > "$ykcowrebbaj.xdig"
    # Now use 'sed' in a safe (no special chrs) way.
    # Note, all files are now each, a single line  ('\n' is now '0A')
      sed -i "s/$(cat "$jabberwocky.xdig")/$(cat "$ykcowrebbaj.xdig")/p" "$lookinglass.xdig"
    
      ##### This section if FOR CHECKING THE RESULTS ONLY
            # Check result 1
            read -p "About to test for the presence of  'jabberwocky.xdig'  within itself (Enter) "
            sed -n "/$(cat "$jabberwocky.xdig")/p"     "$jabberwocky.xdig"
            echo -e "\n\nA dump above this line, means: 'jabberwocky' is as expected\n" 
            # Check result 2
            read -p "About to test for the presence of  'ykcowrebbaj.xdig'  within itself (Enter) "
            sed -n "/$(cat "$ykcowrebbaj.xdig")/p"     "$ykcowrebbaj.xdig"
            echo -e "\n\nA dump above this line, means: 'ykcowrebbaj' is as expected\n" 
            # Check result 3
            read -p "About to test for the presence of  'lookinglass.xdig'  within itself (Enter) "
            sed -n "/$(cat "$ykcowrebbaj.xdig")/p"     "$lookinglass.xdig"
            echo -e "\n\nA dump above this line, means: 'lookinglass' is as expected\n" 
            # Check result 4
            read -p "About to test for the presence of  'lookinglass.xdig'  within itself (Enter) "
            sed -n "/$(cat "$jabberwocky.xdig")/p"     "$lookinglass.xdig"
            echo -e "\n\nNo dump above this line means: 'lookinglass' is as expected\n"
      ##### End of CHECKING THE RESULTS
    
    # Now convert the hexdump to binary, and overwrite the original
      cat "$lookinglass.xdig" | xxd -r -p > "$lookinglass"
    # Echo the "modified" poem to the screen
      sed -n 322,359p "$lookinglass"
      echo -e "\n\nYou are now looking at the REPLACEMENT text (dumped directly from the source 'book'"
    
    • 2

相关问题

  • 如何从命令行仅安装安全更新?关于如何管理更新的一些提示

  • 如何从命令行刻录双层 dvd iso

  • 如何从命令行判断机器是否需要重新启动?

  • 文件权限如何工作?文件权限用户和组

  • 如何在 Vim 中启用全彩支持?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    我需要什么命令来解压缩/提取 .tar.gz 文件?

    • 8 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Marko Smith

    如何使用命令行将用户添加为新的 sudoer?

    • 7 个回答
  • Marko Smith

    更改文件夹权限和所有权

    • 9 个回答
  • Martin Hope
    EmmyS 我需要什么命令来解压缩/提取 .tar.gz 文件? 2011-02-09 14:50:41 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve