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.

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.

  • 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
10

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
  • 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
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

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.