pynexj
pynexj

Reputation: 20698

Portable sed way to find longest common prefix of strings

The sed solutions in Longest common prefix of two strings in bash only work with GNU sed. I'd like a more portable sed solution (e.g. for BSD/macOS sed, Busybox sed).

Upvotes: 2

Views: 424

Answers (1)

pynexj
pynexj

Reputation: 20698

The following solutions are tested with GNU sed, macOS (10.15) sed and busybox (v1.29) sed.

$ printf '%s\n' a ab abc | sed -e '$q;N;s/^\(.*\).*\n\1.*$/\1/;h;G;D'
a
$ printf '%s\n' a b c    | sed -e '$q;N;s/^\(.*\).*\n\1.*$/\1/;h;G;D'

$

To be more efficient when there are many strings especially when there's no common prefix at all (note the ..* part which is different from the previous solution):

$ printf '%s\n' a ab abc | sed -ne :L -e '$p;N;s/^\(..*\).*\n\1.*/\1/;tL' -e q
a
$ printf '%s\n' a b c    | sed -ne :L -e '$p;N;s/^\(..*\).*\n\1.*/\1/;tL' -e q
$

Regarding $q in the first solution

According to GNU sed manual (info sed):

  • N command on the last line

    Most versions of sed exit without printing anything when the N command is issued on the last line of a file. GNU sed prints pattern space before exiting unless of course the -n command switch has been specified.


Note that I did not use sed -E because macOS' sed -E does not support \N back-reference in s/pattern/replace/ command's pattern part.

  • With GNU sed:

    $ echo foofoo | gsed -E 's/(foo)\1/bar/'
    bar
    
  • With macOS sed:

    $ echo foofoo | sed  -E 's/(foo)\1/bar/'
    foofoo
    

UPDATE (2021-04-26):

Found this in another answer :

sed -e '1{h;d;}' -e 'G;s/\(.*\).*\n\1.*/\1/;h;$!d'

Note that it does not work when the input includes only one line. Can be easily fixed by removing the 1d part:

sed -e '1h;G;s/^\(.*\).*\n\1.*/\1/;h;$!d'

Upvotes: 5

Related Questions