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.


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


  • 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'
  • 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
  • 1
    @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 'SO- stop being evil' 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
  • 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 clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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