5

I have this string

extension_dir => /some/path/php/extensions/no-debug-non-zts-20160303 => /some/path/php/extensions/no-debug-non-zts-20160303
sqlite3.extension_dir => no value => no value

which is the output of php -i | grep extension_dir.

How can I parse it in bash to get the first /some/path/php/extensions/no-debug-non-zts-20160303?

So far I have tried:

echo $(php -i | grep extension_dir | sed 's/extension_dir => //g' | sed 's/=> .*//g')

but that gives me /some/path/php/extensions/no-debug-non-zts-20160303 sqlite3.no value. I have no idea why it doesn't replace all matches of => .*

My base idea is to get rid of first extension_dir => and than rid of everything after first => including => Probably sed matches things differently than regex.

  • 1
    What is the exact output you want? It looks like it's done just what you described: all matches of => .* have been removed. – JigglyNaga Feb 16 '18 at 12:59
  • There are two ouput lines instead of one and therefore sed doesn't work. I wanted to get /some/path/php/extensions/no-debug-non-zts-20160303 – simPod Feb 16 '18 at 13:01
8
php -i | sed -n '/extension_dir/{s/^[^/]*//;s/ *=>.*$//;p;}'

or, as suggested in comments below,

php -i | sed '/extension_dir/!d;s/[^/]*//;s/ *=>.*//'

The sed above replaces your grep and will, for every line that matches extensions_dir, first remove everything up to the first / and then everything from the first => onwards in the modified string. Any spaces before the => are also removed. Lines not matching extensions_dir are ignored.

This will return the wanted path for the first line of input, and an empty line for the second.

To disregard the second line of input, use /^extension_dir/ instead of /extension_dir/ in the sed above. This will discard the second line since does not start with that string.


It's the combination of your two sed scripts that produces the surprising result for the second line of input.

The line is

sqlite3.extension_dir => no value => no value

and the first sed will modify this to

sqlite3.no value => no value

The second sed will then remove the => no value bit at the end.


Note that

echo $( ... )

is a bit useless as it gobbles up the newlines in the output of the command inside $( ... ). Instead test with just the command without the echo or the $( ... ) command substitution.

It is possibly this use of echo that has had you confused about the nature of the output from php -i and grep (two matching lines rather than one).

  • 1
    Shorter, and IMHO easier to read by deleting the inverted match instead of -n and {...;p}. And the anchors ^ and $ seem superfluous in this case, so sed '/extension_dir/!d;s/[^/]*//;s/ *=>.*//' would do the same job. – Philippos Feb 16 '18 at 12:04
  • @Kusalananda I was thinking that sqlite3.no value would be taken away with matching the first => in => /some/path/php/extensions/no-debug-non-zts-20160303 sqlite3.no value => no value. So this would have been matched => /some/path/php/extensions/no-debug-non-zts-20160303 sqlite3.no value. Why was only => /some/path/php/extensions/no-debug-non-zts-20160303 matched? – simPod Feb 16 '18 at 12:29
  • 1
    @simPod Because sed processes its input data line by line, and you have two separate lines of input. – Kusalananda Feb 16 '18 at 12:31
  • 1
    Thanks for more detailed explaination of my sed use – simPod Feb 16 '18 at 13:02
  • @Philippos: Well, in my humble opinion, “process the lines that match this pattern” is clearer than “process all lines except for the ones that don’t match this pattern” (double negative).  But I suppose some people may be confused by -n and p. – Scott Feb 18 '18 at 20:23
7

I can give you a simple awk solution.

php -i | awk -F ' => ' '/extension_dir/{print $2; exit}'

That will work if you want to lose the sed.

EDIT: Moved exit to inside the block to avoid a syntax error, added spaces around field separator so they won't be output with the resulting filepath, and describe change in body, so stackexchange allows the edit due to minimum character change limitation.

  • Very simple, thanks! I might probably use this one. However, marked Kusalananda's aswer as accepted as it explains the sed problem and that was the original question. – simPod Feb 16 '18 at 13:05
  • Yes, awk is a much better choice for columnar data such as this - exactly the answer I thought of when I read the question. – Toby Speight Feb 16 '18 at 14:58
2

If path doesn't contain spaces, this expression will be enough:

php -i | grep -Po 'extension_dir => \K/[^ ]*'

Input

extension_dir => /some/path/php/extensions/no-debug-non-zts-20160303 => /some/path/php/extensions/no-debug-non-zts-20160303
sqlite3.extension_dir => no value => no value

Output

/some/path/php/extensions/no-debug-non-zts-20160303

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.