0

I need to print a string which is in a unique line in a long text file. Example relevant line in file long.txt:

Software version 4.0.10, 2002-03-28

The wanted string is exactly 4.0.10.

The steps probably are:

  • Match the line; e.g. with a regexp such as /^Software/
  • Once the line has been found, perform a search on it for the wanted string (another regexp)
  • Print the string

How can I accomplish this in one line (no pipes pls) with tools such as sed, awk or perl?

Note: The actual regex isn't so relevant. What matters most is the commands and syntax involved. Thanks!

  • 1
    The trick about translating such a description into working code is that we must inevitably make assumptions about your input. Does the desired number always occur just before a comma (as I have assumed)? Does it always occur after exactly two whitespace-separated words, and end in a comma followed by whitespace (as Jay has assumed)? – Wildcard Mar 29 '16 at 0:58
  • Yes, I understand. But actually the important part here is not so much a singular regexp but how apply a command to a previous command output. IMO the answers, yours in particular, are very useful! – undostres Mar 29 '16 at 15:19
1

Here are some options for you

sed -n 's/Software version \([^,]\+\).*/\1/p' file
awk -F '[ ,]' '$1=="Software" && $2=="version" {print $3}' file
perl -nE '/Software version (.+?),/ and say $1' file
grep -oP '(?<=Software version ).+?(?=,)' file

All assume there are no commas in the version string.

2

Your question is quite general; I want to take a moment to discuss the design of sed and how it works to handle such use cases.

sed is the stream editor. It accepts text input in a stream—whether from a pipe, from a single file, or from a sequence of files one after the other—performs actions on that text stream, and outputs text. (Note that it is not intended or designed for file editing in its original conception, though it is often pressed into service for that purpose.)

The keynotes of sed's operation that you should understand, are:

  • sed deals with text line by line. The command(s) you give is essentially a loop that operates on every line of input (by default), and prints the result at the end (by default).
  • A command in sed consists of an optional conditional test (or "pattern") and an action to be performed.
  • All the actions are a single character command, e.g. print, substitute, delete
  • The most common condition is a regex to be matched against the line, but line numbers can be used as well.
  • A range can be specified, meaning: Do the following action for all lines from (first condition) up to (second condition).

There is a very thorough tutorial and reference on sed available free online, which I recommend reading in full.

For your scenario, the command you want is something like:

sed -n -e '/^Software/{s/,.*//;s/.*[[:space:]]//;p;}' filename

Which translates to:

  • -n: suppress sed's default action of printing each line of input
  • -e: Execute following sed command
  • /^Software/: Perform the following set of commands contained in {}, only on lines which match this regex
  • s/,.*//: Remove the first comma from the line (and everything after it)
  • s/.*[[:space:]]//: Remove everything up to the last whitespace character in the line
  • p: Print the resulting text.
  • Thank you for explaining what sed is about. I see several details such as using ; to separate between commands. – undostres Mar 29 '16 at 15:27
1

Give this tested version a try:

 awk '{if ($0 ~ /^Software/) {print substr($3,1,length($3)-1)}}' long.txt

It prints the 3rd element of each line starting with Software.

substr is used to removed the last char ',' from the 3rd element.

The test:

awk '{if ($0 ~ /^Software/) {print substr($3,1,length($3)-1)}}' long.txt
4.0.10
  • 1
    Or just awk '/^Software/ {print substr($3,1,length($3)-1)}' long.txt. You don't need the if construct very often in awk, and essentially never for simple one-liners; awk has the same "condition -> action" syntax design as sed. – Wildcard Mar 29 '16 at 0:56
  • I tried first but it is generating a syntax error with awk installed on the linux debian I use for the tests. – Jay jargot Mar 29 '16 at 6:38
  • Maybe someone could explain me why my awk cannot use the syntax described in the Bruce Bernett's tutorial? FIRST awk is a symbolic links to mawk. Linux debian 2.6.32-5-amd64 ||| squeeze 6.0.10 ||| gawk (1:3.1.7.dfsg-5), mawk (1.3.3-15), original-awk (2010-05-23-1) – Jay jargot Mar 29 '16 at 7:57
  • @Jay You can use sudo update-alternatives --config awk to change the /usr/bin/awk symlink between awk versions. – undostres Mar 29 '16 at 15:23
  • @undostres it wrote an error like no other alternatives.... Thx anyway. – Jay jargot Mar 30 '16 at 23:51

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.