Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

let's present my problem to explain better. I'm using cygwin, the installation is based on a setup.ini with the following format:

    @ 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

then comes the following package, & so forth.

what I need is, given a package name output all packages required by this package (without the 'requires' prefix, if possible).

I'm sure it's basic grep, but I'm new there. thanks.

share|improve this question
up vote 5 down vote accepted

I am not sure how will you do it with grep, but for such tasks I prefer awk. It gives more control over what I want to do. though I am not expert in awk and still learning but here is how I would have achieved this.

PKGNAM="package-name"; awk "/$PKGNAM\$/,/requires:/ { if ( \$0 ~ /requires:/ ) { sub( /^requires:.?/, \"\"  ); print } }"

UPDATE: updated the example awk command, now it uses the PKGNAM variable to match the pacakge name.

enter image description here


share|improve this answer
good answer, I will vote you up when I will have enough reputation (or accept your answer if it's the best after a time). just to make it clear, you have to write /package-name$/ as there are many matches between packages (like GConf2 & GConf2-devel). – Philomath Jul 11 '11 at 14:16
one problem though, how can I replace package-name with a variable? (I need to use it in a script), var expansion doesn't work when surrounded with single quotes, and double quotes spoil the awk script. – Philomath Jul 11 '11 at 14:38
See I told you there must be better ways of doing it, and Gilles already told you 4 awesome different ways of doing this. I have updated my answer too to demonstrate the use of variable name. – Hameedullah Khan Jul 11 '11 at 19:48
thanks for all who answered, I just love the simplicity of this answer. KISS! – Philomath Jul 17 '11 at 0:26

Grep treats all lines independently, so it can't do the job on its own.

Awk is a general text processing tool. Keep track of what the current package is (in the variable p), and output a match if a requires: line is found in the right package (removing the requires: prefix).

<setup.ini awk -vpackage='NAME_OF_PACKAGE' '
    sub(/^@ */,"") {p=$0}
    p==package && sub(/^requires: */,"") {print}

Another awk approach is to process input delimited by newline-@ sequences rather than newlines. Or, since package sections have a blank line between them, process input by paragraph: pass an empty string as the record separator RS (which means that records are separated by one or more blank line). Then, for each line in the sought-after record, if the line begins with requires:, print it (minus the prefix).

<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}

Another possibility is Perl's paragraph mode (-00). If the paragraph starts with the right header (/REGEXP/m means a multiline match, so that the $ anchor means end-of-line rather than end-of-string), and it contains a requires: line, then print that line (minus the prefix).

<setup.ini package=NAME_OF_PACKAGE perl -00 -ne '
    /\A@ *$ENV{package}$/m and /^requires: *(.*)$/m and print "$1\n"'

And here's one for the (GNU) sed lovers . (You are not expected to understand this.)

sed -ne '/^@/ { h; b; }; G; s/^requires: *\(.*\)\n@ *NAME_OF_PACKAGE$/\1/p'
share|improve this answer
wow! that's magic! I definitely have much to learn. just curios, which of them is expected to be the fastest?, we are speaking about thousands of packages. – Philomath Jul 11 '11 at 15:05
@Pilomath The difference in speed will be negligible. Thousands is not much for a computer. However, if you were going to do this for every package, it would be a lot faster to handle them all at once: put the reading and the logic inside the same program (Perl or Python would be more appropriate than the shell). – Gilles Jul 11 '11 at 15:30
of course, but I'm Just Another non - {Perl, Python} Hacker. – Philomath Jul 12 '11 at 3:52

Here's a sed solution that can do it without a back reference.

# cf. "3.3. Addressing and address ranges",
# http://sed.sourceforge.net/sedfaq3.html#s3.3 (esp. (6) Relentless. ...)

sed -ne '/^ *@ *'"${PKGNAME}"'/{
/\n *requires: /!ba
s/.*\n *requires: *//
}' setup.ini 

Gilles' (GNU) sed solutions works on Mac OS X 10.6.7 (using FreeBSD sed) if the b command is put on a separate line (or at least followed by a line break).

sed -ne '/^ *@ *'"${PKGNAME}"'/{h
};G;s/^ *requires: *\(.*\)\n *@ *'"${PKGNAME}"' *$/\1/p' setup.ini
share|improve this answer
Good answer, just replace ${PKGNAME} with ${PKGNAME}\$ to make sure GConf2 doesn't match GConf2-devel. – Philomath Jul 13 '11 at 0:26

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.