【问题标题】:How can I return the entire contents of a split line based on a search?如何根据搜索返回分割线的全部内容?
【发布时间】:2014-08-15 05:28:37
【问题描述】:

posted previously 关于我正在编写的一个小脚本。我最终想通了这个问题。现在我遇到了另一个问题。希望您能提供帮助。

一些设置:我有一个存储为降价文件的短列表。

|One Hundred Years of Solitude|Gabriel García Márquez|-|-|-|-|1967|
|Moby-Dick|Herman Melville|-|-|-|-|1851|
|Frankenstein|Mary Shelley|-|-|-|-|1818|
|On the Road|Jack Kerouac|-|-|-|-|1957|
|The Turn of the Screw|Henry James|-|-|-|-|-|

我已经弄清楚了如何通过 cat、sed、xargs 和 awk 输入文件。

cat list.md | sed -e 's/^\|//' -e 's/\|$//' -e 's/^ *//' \
-e '/^\:/d' -e '/\'Title'/d' -e '/^\r/d' -e '/^$/d' | xargs -0 echo | \
awk -F '|' '{print "----"} {print "Title:", $1} {print "Author:", $2} \
{print "Date Begun:", $4} {print "Date Finished:", $5}'

该命令返回:

----
Title: One Hundred Years of Solitude
Author: Gabriel García Márquez
Date Begun: -
Date Finished: -
----
Title: Moby-Dick
Author: Herman Melville
Date Begun: -
Date Finished: -
----
Title: Frankenstein
Author: Mary Shelley
Date Begun: -
Date Finished: -
----
Title: On the Road
Author: Jack Kerouac
Date Begun: -
Date Finished: -
----
Title: The Turn of the Screw
Author: Henry James
Date Begun: -
Date Finished: -

我想做的是将它合并到一个脚本中,我可以使用诸如“books Melville”之类的参数运行该脚本,该参数将运行上述命令,将其通过管道输入 grep,搜索参数(最好是单词或一个字符串),然后返回整行。比如,如果我输入“books Melville”,脚本会返回

----
Title: Moby-Dick
Author: Herman Melville
Date Begun: -
Date Finished: -

目前,如果我输入“books Melville”,它返回的只是“作者:Herman Melville”。

抱歉,帖子太长了。

再次道歉编辑:我忘了提到我在 OSX 上。

【问题讨论】:

  • 对于初学者来说,这个长命令似乎非常过于复杂,但话虽如此,为什么不过滤 before 那个转换呢?在我看来,这似乎更简单,只需要 grep。
  • 另外,-e '/\'Title'/d' 并没有按照您的意思行事。它不会逃避第二个',因为你不能在shell 中这样做。这分解为三个字符串:单引号 /\ ,未引用 Title 单引号 /d
  • @EtanReisner 我完全承认该命令可能要简单得多,但我想开始自学正则表达式。至于-e '/\'Title'/d',我只是省略了降价表的前两行,其中包含与该正则表达式对应的字符串。
  • 我并不是说它没有达到您的预期。我建议将字符串放在命令行上的方式可能不是您认为的那样。它不是单引号字符串中的转义单引号,因为单引号字符串不支持这样的转义。 (由于这样你会有三个未转义的单引号,所以计数也会被取消。

标签: bash awk sed cat


【解决方案1】:

我会给你两个小的 awk 脚本(由于多字符 RS,第二个脚本需要 GNU awk。你可以通过使用空间而不是 ---- 并使用 @987654325 使其可移植@段落模式)。第一个脚本是删除所有的混乱并创建一个数据库文件。

$ cat md.file
|One Hundred Years of Solitude|Gabriel García Márquez|-|-|-|-|1967|
|Moby-Dick|Herman Melville|-|-|-|-|1851|
|Frankenstein|Mary Shelley|-|-|-|-|1818|
|On the Road|Jack Kerouac|-|-|-|-|1957|
|The Turn of the Screw|Henry James|-|-|-|-|-|

$ awk -F"[|]" '{
    printf "----\nTitle: %s\nAuthor: %s\nDate Begun: %s\nDate Finished: %s\n", $2, $3, $5, $6
  }' md.file > database.file

现在database.file 看起来像这样:

----
Title: One Hundred Years of Solitude
Author: Gabriel García Márquez
Date Begun: -
Date Finished: -
----
Title: Moby-Dick
Author: Herman Melville
Date Begun: -
Date Finished: -
----
Title: Frankenstein
Author: Mary Shelley
Date Begun: -
Date Finished: -
----
Title: On the Road
Author: Jack Kerouac
Date Begun: -
Date Finished: -
----
Title: The Turn of the Screw
Author: Henry James
Date Begun: -
Date Finished: -

文件准备好后,您可以在bash 脚本或命令行中使用以下awk 脚本,无论您认为哪种方式都合适。

如果您希望从bash 文件运行,您可以创建一个您要搜索的bash 变量。

$ look=Melville
$ echo "$look"
Melville
$ awk -v RS="----" -vlook="$look" '$0~look' database.file

Title: Moby-Dick
Author: Herman Melville
Date Begun: -
Date Finished: -

如果你想绕过 shell 变量,你可以做一个正则表达式搜索。

awk -v RS="----" '/Melville/' database.file

如果您的条件是trueawk 将为您打印。这意味着,上面的陈述就像在说

awk -v RS="----" '/Melville/ { print $0 }' database.file

awk -v RS="----" -vlook="$look" '$0~look { print $0 }' database.file

【讨论】:

  • 在我的第一份工作中,我们使用标准 UNIX™ 工具(其中包括 awk)实现了(除其他外)一个关系数据库,最终得到的结果与您在这里的结果非常相似。
【解决方案2】:

使用 bash:

seek=he
labels=(- Title Author - "Date Begun" "Date Finished")
while IFS='|' read -ra fields; do
    [[ "${fields[*]}" == *"$seek"* ]] || continue
    printf "%s\n" "----"
    for i in 1 2 4 5; do
        printf "%s: %s\n" "${labels[i]}" "${fields[i]}"
    done
done < list.md
----
Title: Frankenstein
Author: Mary Shelley
Date Begun: -
Date Finished: -
----
Title: On the Road
Author: Jack Kerouac
Date Begun: -
Date Finished: -
----
Title: The Turn of the Screw
Author: Henry James
Date Begun: -
Date Finished: -

【讨论】:

    【解决方案3】:

    使用 awk:

    #!/usr/bin/awk -f
    BEGIN {
        if (!(ARGC >= 2)) exit
        search = ARGV[1]
        ARGV[1] = "/complete/path/to/list.md"
        FS = "|"
        OFS = "\n"
    }
    $0 ~ search {
        print "----", "Title: " $2, "Author: " $3, "Date Begun: " $4, "Date Finished: " $5
    }
    

    将值"/complete/path/to/list.md" 更改为真实值。将其保存在$PATH 覆盖的目录中,例如/usr/local/bin,并将其命名为books。将其权限更改为0755,然后使用books Melv 对其进行测试。

    如果您不是以 root 身份运行,为方便起见,请先将其保存到一个临时文件,如 script.awk,进行适当的编辑,然后运行:

    sudo install -m 0755 script.awk /usr/local/bin/books
    

    多个关键字

    此版本允许多个关键字验证搜索:

    #!/usr/bin/awk -f
    BEGIN {
        if (!(ARGC >= 2)) exit
        for (i = 1; i < ARGC; ++i) {
            keywords[k++] = ARGV[i]
        }
        ARGV[1] = "/complete/path/to/list.md"
        ARGC = 2
        FS = "|"
        OFS = "\n"
    }
    $0 ~ keywords[0] {
        for (i = 1; i < k; ++i) {
            if (!($0 ~ keywords[i])) {
                next
            }
        }
        print "----", "Title: " $2, "Author: " $3, "Date Begun: " $4, "Date Finished: " $5
    }
    

    【讨论】:

    • 我应该将文件保存为 books.sh 吗?
    • @a--clam 这是一个 awk 脚本,但您不必为其添加扩展名。如果您真的想以books 而不是books.awk 运行它,请将其放在/usr/local/bin 上作为books。请查看说明。
    • 感谢编辑回复。抱歉,我在回复之前没有检查。我编辑了我原来的帖子也这么说,但是看到我在 OSX 上,我似乎没有傻眼。我该怎么办?
    • @a--clam 其他 awks 只是没有 IGNORECASE。如果关键字不能不区分大小写,可以吗?您只需将标题更改为/usr/bin/awk
    • 单词不区分大小写也没关系。这解决了问题。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-14
    相关资源
    最近更新 更多