【问题标题】:How to set matches in a list, set them to a variable, reformat output and pass it to another script?如何在列表中设置匹配项,将它们设置为变量,重新格式化输出并将其传递给另一个脚本?
【发布时间】:2013-10-30 20:27:51
【问题描述】:

副标题:“我是来学习的。”

我需要将我的几个链接集合从 Markdown 转换为另一种格式(具体来说,通过 this script 将文件中的每一行作为单个笔记发送到 Evernote)。

我的示例文件都是这样的:

* [REF_1](URL)
* [REF_2](URL)
* [REF_3](URL)

编辑:或更准确地说:

* [Koken Installtion Help](http://help.koken.me/customer/portal/articles/632102-installation)
* [A couple of Sass functions](http://hugogiraudel.com/2013/08/12/sass-functions/)
* [Chris Coyier's Favorite CodePen Demos](http://davidwalsh.name/chris-coyiers-favorite-pens)

……这是我的作战计划:

  1. 解析每一行
  2. 去除前导星号/连字符/加号后跟空格^[\*\-\+]\s
  3. 匹配[REF]的内容(方括号之间的所有内容)与正则表达式(?<=\[)(.*)(?=\])并将其设置为变量${titel}
  4. 匹配[URL]的内容(括号之间的所有内容)与正则表达式(?<=\()(.*)(?=\))并将其设置为变量${url}
  5. 如下例所示格式化新输出。
  6. 保存到变量/剪贴板/标准输出(←我不知道哪个效果最好)并在上面运行markdown2evernote.rb
  7. 所有线路都发送? → 完成。

示例(见第 5 点):

Notebook: ${notebook}
Title: ${title}
Url: ${url}
Keywords: ${keywords}

Content Area

Will use the $title and $url variable here again.

坦率地说,我还没有走多远。我已经被困在第二点,因为我不知道如何让正则表达式工作。目前,我的 bash 脚本如下所示:

#!/bin/sh

document=~/file.txt
notebook="My test notebook"
keywords="test, demo"

cat ${document} | while read line; do \
    echo "$line" | sed -e '(?<=\[)(.*)(?=\])'; \
done

我不在乎它是否是一个 sed/grep/awk 解决方案——只要它是一个 shell 脚本,我就接受它。

我还对在检查列表中的第 2 点和第 3 点并达到我可以将格式化输出移交给 ruby​​ 脚本的目标之后继续进行的最佳方式感兴趣。

如上所述,我有一个模糊的想法,但这是一个相当大的挑战,因为到目前为止我编写的脚本要简单得多,并且不涉及上述任何内容。

【问题讨论】:

  • markdown 真的可以用正则表达式解析吗?如果没有,你很快就会遇到两个问题:你原来的问题,加上正则表达式问题。
  • 你的意思是#!/bin/sh,对吧?如果这是您真正打算使用的,最好明确调用#!/bin/bash。仅调用sh 可能会导致不同操作系统出现问题。祝你好运。
  • @shellter 哦,是的,那是个错误。我在我的编辑器中准备了这个问题,并取消了所有行的注释……哈希也消失了。双是:我打算使用#!/bin/bash。会解决的。

标签: regex bash shell match


【解决方案1】:

您可以使用sed 提取变量并写入输出。

sed 's/^[*-+] *\[\(.*\)\](\(.*\))/Notebook: x\nTitle: \1\nUrl: \2\nKeywords: y\n\nContent Area\n\nWill use the \1 and \2 variable here again/' file.txt

通过使用\(\),您可以使用\1\2 等访问这些括号内的模式。

但是,如果您的输出包含大量文本,您将仅使用文本来破坏 sed 命令,使其可读性降低。数据和程序控制结构应该分开,所以我建议这样:

#!/usr/bin/env bash

fillText(){
    echo "Notebook: ${1}"
    echo "Title: ${2}"
    echo "Url: ${3}"
    echo "Keywords: ${4}"
    echo
    echo "Content Area"
    echo
    echo "Will use ${2} and ${3} variable here again."
}

document=file
notebook="My test notebook"
keywords="test, demo"

while read line; do
    title=$(sed 's/^[*-+] *\[\(.*\)\](.*)/\1/' <<< "${line}")
    url=$(sed 's/^[*-+] *\[.*\](\(.*\))/\1/' <<< "${line}")
    fillText "${notebook}" "${title}" "${url}" "${keywords}"
done < "${document}"

函数fillText() 以您喜欢的方式写入输出,它接受四个位置参数,其中两个从"${document}"sed 中提取。

fillText 函数也可以在不同的文件中定义。

顺便说一下,对你代码的某些部分的注释:

cat ${document} | while read line; do \
    echo "$line" | sed -e '(?<=\[)(.*)(?=\])'; \
done

完全一样

sed '(?<=\[)(.*)(?=\])' "${document}"

(尽管我不知道'(?&lt;=\[)(.*)(?=\])'是什么意思。

【讨论】:

  • 感谢您精心设计的解决方案。在函数中使用占位符变量很棒。不知道。不幸的是,我没有准确解释我的需求,因为我使用的是真正的“标题”和“URL”而不是[REF_1](URL)。我在这里概述了所有内容 cl.ly/SFP7> - 所以缺少的一件事 - 我现在失败的地方 - 是正确匹配内容并使用 sed 匹配模式的正确正则表达式。
  • 我的错。它应该从第一次迭代开始就可以工作,但是空格(像往常一样!)把事情搞混了。 sed 命令很好,但是将空格作为位置参数传递给fillText() 却不行。我现在修好了。我们使用sed 两次来获取不同的参数并将其存储在变量中,然后将其传递给fillText()
  • 哇。那是梦想成真。最好的部分是我现在比以前更了解 sed 正则表达式。我将能够为其他项目做出改变。那太棒了。非常感谢。
猜你喜欢
  • 2021-02-12
  • 2022-12-08
  • 2014-10-10
  • 2022-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
相关资源
最近更新 更多