4

I'm working on bash script.

I have a var with a string in it. This is the string:

tSA_15_20161014_11-12-50

Basically the format is tSA_(id)_(year)(month)(day)_(hour)-(min)-(seg)

Important information:

  • The id can be a number from 0 to 999
  • The year format is yyyy
  • Month format mm
  • Day format dd
  • Hour format 24h

The string I want to get is something like:

20161014111250

Which is yyyymmddHHMMSS

English is not my native language, so if there's something you can't understand please tell me. Thank you.

6 Answers 6

12

With bash parameter expansion:

$ var='tSA_15_20161014_11-12-50'

$ var="${var#*_}"  ## Extracts the portion after first `_` i.e. 
                      new `var` will be `15_20161014_11-12-50`

$ var="${var#*_}"  ## again gets the portion after first `_`, so in this case
                      after operation `var` will contain `20161014_11-12-50`

$ echo "${var//[-_]/}"  ## Replaces all `-` and `_` from `$var` with null
20161014111250
3
  • 2
    I like this answer more as you provided a pure bash solution as specified by the OP.
    – Aditya K
    Oct 14, 2016 at 21:59
  • 1
    +1, but every one of those quotes except the very last pair is unnecessary and does nothing. Substitutions inside assignments (second and third line) are not subject to word splitting. And the first like doesn't have any whitespace in it.
    – mtraceur
    Oct 15, 2016 at 3:25
  • @mtraceur I know, that's just the muscle memory :)
    – heemayl
    Oct 15, 2016 at 9:33
8
echo "tSA_15_20161014_11-12-50" | awk -F'_' '{print $3$4}' | tr -d -

echo the var in which the string is stored

Explanation:

awk -F'_' '{print $3$4}' change the field separator to _ and print the 3rd and 4th column

The output is 2016101411-12-50

tr -d - deletes - from the previous result.

2
  • Exactly what I was looking for. Thanks a lot @debal
    – gloaiza
    Oct 14, 2016 at 17:35
  • 1
    Or simply: echo "tSA_15_20161014_11-12-50" | awk -F'_' '{gsub("-", "", $4); print $3$4}'
    – heemayl
    Oct 14, 2016 at 17:41
3

Given

var='tSA_15_20161014_11-12-50'

then

IFS=_ read -a arr <<< "${var//-/}"
printf '%s%s\n' "${arr[2]}" "${arr[3]}"
20161014111250
2

For completeness, a few sed versions:

echo "tSA_15_20161014_11-12-50" \
| sed -rn 's/^tSA_[0-9]{1,3}_([0-9]{8})_([0-9]{2})-([0-9]{2})-([0-9]{2})$/\1\2\3\4/p'

echo "tSA_15_20161014_11-12-50" \
| sed -r 's/^tSA_[0-9]{1,3}_([0-9]{8})_([0-9]{2})-([0-9]{2})-([0-9]{2})$/\1\2\3\4/'

echo "tSA_15_20161014_11-12-50" \
| sed -r 's/([^_]*_){2}(.*)_(.*)/\2\3/;s/-//g'

echo "tSA_15_20161014_11-12-50" \
| sed -r 's/(.*_){3}/\1/;s/[-_]//g'

One thing I find important is error checking. In case the variable does not conform exactly to the format you have given, the first version will yield an empty string, and the second version will yield the input string, unchanged. The third version is a sed version of @debal's awk answer, and the fourth is as concise as I can easily get it, both without specified behavior on incorrect input.

2

Another awk approach. Since awk can take multiple characters as field separators, this can be done in a single step:

$ awk -F'[-_]' '{print $3$4$5$6}' <<<"$var"
20161014111250

Alternatively, in Perl:

$ perl -pe 's/.+?_.+?_//; s/[-_]//g' <<<"$var"
20161014111250

Or

$ perl -F_ -ane 's/-//g for @F; print @F[2..$#F]' <<<"$var"
20161014111250

I'm using here strings, but if your shell doesn't support them just echo $var | command for each command above.

0

Python solution, using re.split() with multiple tokens. Input string is provided as command line argument

$ python -c 'import sys,re;print("".join(re.split("[-_]",sys.argv[1])[2:]))' "tSA_15_20161014_11-12-50"
20161014111250

Similar approach with ruby:

$ ruby -ne 'puts $_.split(/[-_]/)[2..-1].join("")' <<<  "tSA_15_20161014_11-12-50"                                                   
20161014111250

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .