让我们提出我的问题以便更好地解释。我使用的是 cygwin,安装基于以下格式的 setup.ini:
@ package-name
sdesc: "short description, on one line"
ldesc: "long description of arbitrary length, commonly multiple lines"
category: categories in which the packege belonges, one line
requires: packages (libs etc) required by this package, one line
然后是下面的包,等等。
我需要的是,给定一个包名称,输出该包所需的所有包(如果可能,不带“requires”前缀)。
我确信这是基本的 grep,但我是新手。谢谢。
答案1
我不确定你将如何使用 grep 来完成此任务,但对于此类任务我更喜欢 awk。它可以更好地控制我想做的事情。虽然我不是 awk 方面的专家并且仍在学习,但这就是我如何实现这一点的。
PKGNAM="package-name"; awk "/$PKGNAM\$/,/requires:/ { if ( \$0 ~ /requires:/ ) { sub( /^requires:.?/, \"\" ); print } }"
更新:更新了示例 awk 命令,现在它使用 PKGNAM 变量来匹配 pacakge 名称。
HTH。
答案2
Grep 独立处理所有行,因此它无法单独完成这项工作。
awk 是一个通用的文本处理工具。跟踪当前包是什么(在变量 中),如果在正确的包中找到一行,p
则输出匹配项(删除前缀)。requires:
requires:
<setup.ini awk -vpackage='NAME_OF_PACKAGE' '
sub(/^@ */,"") {p=$0}
p==package && sub(/^requires: */,"") {print}
'
另一种 awk 方法是处理由换行符@
序列而不是换行符分隔的输入。或者,由于包部分之间有一个空行,因此按段落处理输入:传递一个空字符串作为记录分隔符RS
(这意味着记录由一个或多个空行分隔)。然后,对于所需记录中的每一行,如果该行以 开头requires:
,则打印它(减去前缀)。
<setup.ini awk -vpackage='NAME_OF_PACKAGE' -vRS= -vFS='\n' '
sub(/^@ */,"") && $1==package {
for (i=2; i<NF; i++) {if (sub(/^requires: */,"",$i)) print $i}
}'
另一种可能性是 Perl 的段落模式 ( -00
)。如果段落以右标题开头(/REGEXP/m
表示多行匹配,因此$
锚点表示行尾而不是字符串尾),并且它包含一行requires:
,则打印该行(减去前缀)。
<setup.ini package=NAME_OF_PACKAGE perl -00 -ne '
/\A@ *$ENV{package}$/m and /^requires: *(.*)$/m and print "$1\n"'
这是为 (GNU) sed 爱好者准备的。 (你不应该理解这一点。)
sed -ne '/^@/ { h; b; }; G; s/^requires: *\(.*\)\n@ *NAME_OF_PACKAGE$/\1/p'
答案3
这是一个sed
无需反向引用即可完成此操作的解决方案。
# cf. "3.3. Addressing and address ranges",
# http://sed.sourceforge.net/sedfaq3.html#s3.3 (esp. (6) Relentless. ...)
PKGNAME="package-name"
sed -ne '/^ *@ *'"${PKGNAME}"'/{
:a
N
/\n *requires: /!ba
s/.*\n *requires: *//
p
}' setup.ini
如果命令放在单独的行上(或者至少后面有一个换行符),Gilles(GNU)的sed
解决方案可以在 Mac OS X 10.6.7(使用 FreeBSD sed)上运行。b
PKGNAME="package-name"
sed -ne '/^ *@ *'"${PKGNAME}"'/{h
b
};G;s/^ *requires: *\(.*\)\n *@ *'"${PKGNAME}"' *$/\1/p' setup.ini