wheeler
wheeler

Reputation: 3251

sed not liking regex syntax

I am trying to run the following command on a file to get the first 3 parts of the version number:

sed -nE 's/^([\d.]+)(?=\.)/\1/' version

The file is as follows:

1.2.3.4

I am expecting 1.2.3 to output as per the regex I tested on regexr but for some reason there is an inconsistency between regexr's syntax and what sed expects and I keep on getting the following errors:

sed: -e expression #1, char 21: Invalid preceding regular expression

Upvotes: 1

Views: 116

Answers (2)

Charles Duffy
Charles Duffy

Reputation: 295904

The only functionality sed is guaranteed to provide is that given in its POSIX specification. This refers in turn to the POSIX Basic Regular Expressions syntax, with a very limited set of guaranteed extensions. By contrast, both (?=...) and \d are PCRE extensions, not even available in POSIX ERE.


sed supports BRE (by default), or ERE (with platform-specific extensions such as -r or -E). \d is not part of either of these; neither is (?=...).

An ERE equivalent would be:

sed -Ee 's/^([[:digit:].]+)[.][^.]*$/\1/' version

...or a BRE equivalent (working with baseline POSIX sed):

sed -e 's/[.][[:digit:]]\{1,\}$//' version

...or, even better, not using sed at all but sticking to bash built-in capabilities:

full_version=$(<version)   # or full_version=$(cat version) on non-bash shells
version=${full_version%.*} # trim everything after the last "."

Upvotes: 2

mklement0
mklement0

Reputation: 440471

To complement Charles Duffy's helpful answer:

If the only content of your version file is a version number, the following bash commands are an alternative if you want a fixed number of components:

 IFS='.' read -r maj min rev _ < version
 ver=$maj.$min.$rev  # with the sample input, $ver is now '1.2.3'

This extracts only the first 3 .-separated tokens from the (first line of the) input (the remainder of the line, if any, is assigned to unused var. $_), and then rebuilds them into a 3-component version number.


A perl alternative (which is a bit heavy-handed for a single version number; lines that don't match are passed through as-is):

perl -pe 's/^((\d+\.){3}).*/$1/; s/\.$//' version

Upvotes: 0

Related Questions