divinedragon
divinedragon

Reputation: 5346

Replacement within the matched string with sed

I have a property file for java like below.

server.port=8080
spring.application.name=app1
spring.datasource.driver-class-name=org.mysql.jdbc.Driver

I want to convert the file to a linux equivalent property file like below.

SERVER_PORT=8080
SPRING_APPLICATION_NAME=app1
SPRING_DATASOURCE_DRIVER_CLASS_NAME=org.mysql.jdbc.Driver

I am using sed, and I am able to convert the property names with the following sed command.

sed "s/^\(.*\)=\(.*\)$/\U\1=\E\2/" application.properties

However, I am not able to figure out how to replace the dots(.) with underscore(_) character in the matched part(\1).

Can somebody help?

Upvotes: 1

Views: 178

Answers (4)

mklement0
mklement0

Reputation: 437783

An alternative perl solution that is perhaps conceptually simpler: Tip of the hat to @Sundeep for his help with simplifying the command.

perl -F'(=)' -ane '$F[0] = uc $F[0] =~ tr/./_/r; print @F' application.properties
  • -F(=), combined with -a, splits each input line into fields by =. (-n suppresses default output, and -e tells Perl to treat the next operand as a command).
    Enclosing = in (...) also makes the = instances part of the field array stored in @F.

  • $F[0] =~ tr/./_/r translates all literal . chars. into _ chars. in the 1st field (the property name) and returns the result, thanks to the r option.

  • $F[0] = uc then converts the result to all-uppercase and updates the 1st field with the result.

  • print @F then prints all fields, starting with the modified 1st field, separated by = (the output field separators that were also captured in @F), in effect printing the upper-cased 1st input field with . chars. translated to _, followed by = and the unmodified remainder of the input line.

Upvotes: 2

Sundeep
Sundeep

Reputation: 23667

If perl is okay:

$ perl -pe 's/^.*=/\U$&/; s/^.*=/$&=~s|\.|_|gr/e' application.properties 
SERVER_PORT=8080
SPRING_APPLICATION_NAME=app1
SPRING_DATASOURCE_DRIVER-CLASS-NAME=org.mysql.jdbc.Driver
  • s/^.*=/$&=~s|\.|_|gr/e use another substitution for captured text ^.*=

Can be simplified to

$ perl -pe 's/^.*=/uc $&=~s|\.|_|gr/e' application.properties 
SERVER_PORT=8080
SPRING_APPLICATION_NAME=app1
SPRING_DATASOURCE_DRIVER-CLASS-NAME=org.mysql.jdbc.Driver


With sed

$ sed 's/^.*=/\U&/; :a s/^\([^=]*\)\./\1_/g; ta' application.properties 
SERVER_PORT=8080
SPRING_APPLICATION_NAME=app1
SPRING_DATASOURCE_DRIVER-CLASS-NAME=org.mysql.jdbc.Driver
  • :a s/^\([^=]*\)\./\1_/g; ta replace . with _ until the text before . doesn't contain =


If both . and - before = needs to be changed to _, use [.-] instead of \. in both solutions

Upvotes: 2

Benjamin W.
Benjamin W.

Reputation: 52132

With cut, tr, paste and process substitution (requires Bash):

$ paste -d= <(cut -f1 -d= application.properties | tr '[:lower:].-' '[:upper:]_') \
>           <(cut -f2 -d= application.properties)
SERVER_PORT=8080
SPRING_APPLICATION_NAME=app1
SPRING_DATASOURCE_DRIVER_CLASS_NAME=org.mysql.jdbc.Driver

Both cut and paste use = as the delimiter, and the first cut pipes to tr for uppercasing and replacing periods and dashes with underscores.

Upvotes: 2

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89557

You can use a conditional loop:

sed 's/^[^=]*/\U&/;:a;s/^\([^=]*\)[.-]/\1_/;ta'

Where ta jumps to the label "a" as long as something is replaced.

With awk:

awk -F= -vOFS='=' '{$1=toupper($1);gsub("[-.]", "_", $1)}1'

Upvotes: 2

Related Questions