【问题标题】:formating each string comming out of Grep格式化来自 Grep 的每个字符串
【发布时间】:2014-01-28 08:18:04
【问题描述】:

这是作业!

我正在编写一个 shell 脚本,它本质上将创建一个书籍数据库,包含所有已输入书籍的文件看起来像

J.K.罗琳:哈利波特:我不知道:200 年代
作者 1:title1:Publisher1:year1
作者2:title2:Publisher2:year2
.
.
.
作者(n):title(n):Publisher(n):year(n)

现在我使用 grep 搜索在命令行中输入的特定搜索模式,比如说“Harry Potter”,然后它将输出所有带有字符串“Harry potter in it”的条目

我有这个工作

grep $2 "bookprint.txt"

但是它打印出的所有内容都与输入文件中的内容相同...。作者 1:title1:Publisher1:year1

但是我想格式化字符串,这样它会打印 4 个单独的行,每行分成 2 列,所以输出看起来像

作者(S):..J.K.罗琳
标题:............哈利波特
发布者:...我不知道
年份:........2000 年代
(假设句点是空格,我无法正确格式化它们以显示我想要的)

这里的任何提示将不胜感激

【问题讨论】:

    标签: shell unix file-io


    【解决方案1】:

    仅使用 sed 和 grep:

    grep "$2" "bookprint.txt" | sed 's/^/Author(s)! /; s/:/\nTitle!     /; s/:/\nPublisher! /; s/:/\nYear!      /; s/!/:/g' 
    

    在您的示例上对其进行测试以显示 sed 命令的示例输出:

    $ echo "J.K. Rowling:Harry Potter:I dont know:2000's" | sed 's/^/Author(s)! /; s/:/\nTitle!     /; s/:/\nPublisher! /; s/:/\nYear!      /; s/!/:/g' 
    Author(s): J.K. Rowling
    Title:     Harry Potter
    Publisher: I dont know
    Year:      2000's
    

    工作原理: sed 进行了五次替换。一般来说,每个替换工作看起来像`s/old/new/'。这指示 sed 查找“旧”的第一次出现并将其替换为“新”。因此,例如:

    $ echo "this is so old" | sed 's/old/new/'
    this is so new
    

    我们使用的第一个替代品是:

    s/^/Author(s)! /
    

    对于 sed,插入符号 (^) 是一个特殊字符,它与行首匹配。因此,这种替换会导致“Author(s)!”被放置在行首。

    第二个替代命令是

    s/:/\nTitle!     /
    

    这会导致第一次出现的冒号 (":") 被替换为 "\nTitle!",其中 \n 被视为换行符。

    如果我们刚刚使用了这两个命令,结果将是:

    $ echo "J.K. Rowling:Harry Potter:I dont know:2000's" | sed 's/^/Author(s)! /; s/:/\nTitle!     /' 
    Author(s)! J.K. Rowling
    Title!     Harry Potter:I dont know:2000's
    

    所以,我们仍然需要输入出版商和年份。

    查看上面的输出,您会看到,在完成上面的两次替换后,第一个冒号出现在出版商名称之前。所以,第三个替代命令是:

    s/:/\nPublisher! /
    

    此命令将第一次出现的冒号 (":") 替换为 "\nPublisher!"。年份行的创建方式与替换相同:

    s/:/\nYear!      /
    

    只有这四个替换,我们将:

    $ echo "J.K. Rowling:Harry Potter:I dont know:2000's" | sed 's/^/Author(s)! /; s/:/\nTitle!     /; s/:/\nPublisher! /; s/:/\nYear!      /' 
    Author(s)! J.K. Rowling
    Title!     Harry Potter
    Publisher! I dont know
    Year!      2000's
    

    这看起来不错,只是我们在需要冒号的地方有感叹号。所以,我们需要的最后一个替换是:

    s/!/:/g
    

    注意末尾的“g”。这告诉 sed 在全球范围内进行这种替换。因此,这个替换告诉 sed 用冒号替换 every 感叹号。这给出了您想要的结果。

    【讨论】:

    • 哇,谢谢!我是新手,所有的斜线和东西仍然让我感到困惑,你能推荐一个好的指南/网站,我可以在其中阅读“s/^/Author(s)!/;”它到底是如何工作的,所以我将来可以创造这样的东西?
    • @cooooookiemonster 我已经添加了一个解释作为开始。有关基础知识的更多信息,bash 简介是 here,sed 简介是 here
    【解决方案2】:

    我建议尝试gawk 来完成此类任务(尽管可以使用纯bash 来完成)。使用gawk,您可以这样做:

    gawk -v SEARCH="${2}" -F ":" '$0 ~ SEARCH {for (i=1;i<=NF;i++) { print $i }}'
    
    1. 这会将您的搜索字符串传递给gawk (-v SEARCH="${2})
    2. 设置输入文件的字段分隔符 (-F ":")
    3. 在每一行 ($0) 中搜索您的搜索字符串
    4. 对于每个匹配项,将该行中的每个字段打印在单独的行上

    没有gawk(和sed):

    IFS=":" read -a array <<< $(grep $2 bookprint.txt)
    for element in "${array[@]}"
    do
        echo "$element"
    done
    

    注意只有在只有一条匹配记录时才有效。更多记录是可行的,但是我们不是来解决你的作业的。您应该自己研究和尝试解决方案。并阅读精美的手册。并学习。

    【讨论】:

    • 我认为我不允许使用该命令我认为我只允许使用 find、sed 和 grep
    • 可以用sed完成。我会看看我是否能找到答案。
    【解决方案3】:

    除了shell,你不需要任何东西来解析和格式化:

    grep "$2" bookprint.txt | while IFS=: read -r author title publisher year; do
        echo "Author(S):  $author"
        echo "Title:      $title"
        echo "Publisher:  $publisher"
        echo "Year:       $year"
    done
    

    非常在 grep 命令中引用 "$2" 很重要:如果 $2 包含“Harry Potter”,grep 会给您一个错误,例如“no such file: Potter”(假设您没有有一个名为 Potter 的文件)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-08
      • 1970-01-01
      • 2016-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-22
      相关资源
      最近更新 更多