I'm working on bash script.

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


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:


Which is yyyymmddHHMMSS

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

echo "tSA_15_20161014_11-12-50" | awk -F'_' '{print $3$4}' | tr -d -

echo the var in which the string is stored


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.

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

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
  • 1
    I like this answer more as you provided a pure bash solution as specified by the OP. – Aditya K Oct 14 '16 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 '16 at 3:25
  • @mtraceur I know, that's just the muscle memory :) – heemayl Oct 15 '16 at 9:33




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

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.


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"

Alternatively, in Perl:

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


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

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


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"

Similar approach with ruby:

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.