1

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?

divinedragon
  • 5,105
  • 13
  • 50
  • 97

4 Answers4

2

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

Sundeep
  • 23,246
  • 2
  • 28
  • 103
2

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'
Casimir et Hippolyte
  • 88,009
  • 5
  • 94
  • 125
2

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.

Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    good one, can also use `perl -F'/(=)/' -ane '$F[0] =~ tr/./_/; $F[0] = uc $F[0]; print @F'` – Sundeep Nov 07 '16 at 06:41
  • 1
    also, using `r` modifier --> `$F[0] = uc $F[0] =~ tr/./_/r` – Sundeep Nov 07 '16 at 06:52
  • `$,` by default has no character separation defined, isn't it? check out `perl -le '@a = (1, "abc", 5); print @a'` vs `perl -le '@a = (1, "abc", 5); print "@a"'` and `perl -le '@a = (1, "abc", 5); $,=":"; print @a'` – Sundeep Nov 07 '16 at 07:19
  • 1
    `-F'(=)'` means the separation character `=` is also saved in `@F` array... check `perl -F'(=)' -lane 'print $F[1]'` vs `perl -F'=' -lane 'print $F[1]'` – Sundeep Nov 07 '16 at 07:22
  • 1
    @Sundeep: Got it; I had a misconception about what using a capture group with `-F` does; corrected now. And to answer my own question: that capture groups used with `-F` add the separators to the fields array is described in the help topic for the [`split` function](http://perldoc.perl.org/5.24.0/functions/split.html) – mklement0 Nov 07 '16 at 07:30
  • @Sundeep: As a minor point of interest: Using the capture-group-in-field-separator approach is conceptually _simpler_, but seemingly _slower_ in terms of execution: when I tried it as an alternative solution with the benchmarks in [this answer](http://stackoverflow.com/a/40414542/45375) of mine, it was noticeably slower (though that will only matter with large input sets). – mklement0 Nov 07 '16 at 07:50
  • 1
    probably because `print @F` would still need a loop and use `$,` which we were doing similar with join anyway.. but incurring extra penalty for capturing the separator.. – Sundeep Nov 07 '16 at 07:57
2

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.

mklement0
  • 382,024
  • 64
  • 607
  • 775
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
  • 1
    ++ for conceptual simplicity, even though multiple child processes are involved (probably won't matter in this case). – mklement0 Nov 07 '16 at 06:42