Łukasz Zaroda
Łukasz Zaroda

Reputation: 767

sed: How to extract only first occurance of value

I have file settings.inc.php with the following content:

<?php
define('_DB_SERVER_', 'mariadb');
define('_DB_NAME_', 'organic');
define('_DB_USER_', 'prestashop');
define('_DB_PASSWD_', 'prestashop');

I want to extract these values to bash, so I managed to create the following command:

sed -rn 's/^.*_DB_NAME_'\'', '\''(\w+)'\''\);/\1/p' settings.inc.php

This will return organic, just as it should, but I would like to improve it further. Let's say we would have this kind of file:

<?php
define('_DB_SERVER_', 'mariadb');
define('_DB_NAME_', 'organic1');
define('_DB_NAME_', 'organic2');
define('_DB_USER_', 'prestashop');
define('_DB_PASSWD_', 'prestashop');

Using above command on this file we would get:

organic1
organic2

The thing is: I want for this command to always return only one value, so let's say the first one. Can I achieve that without piping result into second command?

Upvotes: 3

Views: 3571

Answers (4)

Kisoma
Kisoma

Reputation: 11

Pipe your sed command to head and select the first row as show below:

sed -rn 's/^.*_DB_NAME_'\'', '\''(\w+)'\''\);/\1/p' settings.inc.php | head -1

Upvotes: 1

Sundeep
Sundeep

Reputation: 23697

Can also use awk

$ awk -F "'" '$2=="_DB_NAME_"{print $4; exit}' settings.inc.php 
organic1
  • -F "'" use single quotes as input field separator
  • $2=="_DB_NAME_" check if second field is _DB_NAME_
  • print $4 if condition satisfies, print 4th field
  • exit as only first match is needed

Upvotes: 2

randomir
randomir

Reputation: 18697

If you convert your substitute command followed by print to a command block operating only on lines addressed by pattern (containing) _DB_NAME_, you can quit after the first match/print:

$ sed -rn "/_DB_NAME_/ { s/.*'(\w+)'\);$/\1/p;q }" settings.inc.php
organic1

Note the q command after p.

Also, your sed script can be simplified by using outer double quotes and anchoring on the end.

Upvotes: 0

Eric Renouf
Eric Renouf

Reputation: 14520

With GNU grep you could do it:

grep -m1 -Po "_DB_NAME_', '\K[^']+" settings.inc.php

The grep arguments are:

  • -m 1: stops the search after 1 match
  • -P: turns on Perl style regex (so we can use \K here)
  • -o: only print the part of the line that matches the pattern

The \K part of the pattern says not to include everything up to that point as part of the match, we then have the rest of the pattern finding everything that's not a '.

If you wanted to stick with sed you could find the _DB_NAME_ line, then quit after you found it:

 sed -rn '/_DB_NAME/ {s/^.*_DB_NAME_'\'', '\''(\w+)'\''\);/\1/;p;q}' settings.inc.php

which matches _DB_NAME_ then goes into the block that does your substitution, prints the line, then quits

Upvotes: 3

Related Questions