-3

I have a string like 1001.2001.3001.5001.6001 or 1001-2001-3001-5001-6001. How to extract the 4th string i.e., 5001, add a value like 121 to it and put it back in the same string. The output should be like 1001.2001.3001.5122.6001 or 1001-2001-3001-5122-6001. I have to achieve this in Linux bash scripting.

Jens
  • 69,818
  • 15
  • 125
  • 179
  • 3
    What did you try for yourself? – Inian May 13 '17 at 06:54
  • You should probably check [here](https://stackoverflow.com/a/428118/6381711). – nyedidikeke May 13 '17 at 07:05
  • The bottleneck here is that you've multiple delims.This [\[ answer \]](http://stackoverflow.com/a/39326264/1620779) nicely points a workaround provided you've GNU awk – sjsam May 13 '17 at 08:14
  • Without any attempt it would seem like you just want someone else to do the work for you. This could all be done with simple bash substitution. – grail May 13 '17 at 09:39

5 Answers5

1

Try this

#!/bin/bash
str=$1 
if [[ $(echo $str | grep '\.'  | wc -l) == 1 ]]
then
   str1=$(echo $str |  cut -d '.' -f 1,2,3)
   str2=$(echo $str | cut -d '.' -f 4 | awk {'print $1+121'})
   str3=$(echo $str |  cut -d '.' -f 5)
   echo $str1.$str2.$str3

elif [[ $(echo $str | grep - | wc -l) == 1 ]]
then
    str1=$(echo $str |  cut -d '-' -f 1,2,3)
    str2=$(echo $str | cut -d '-' -f 4 | awk {'print $1+121'})
    str3=$(echo $str |  cut -d '-' -f 5) 
    echo $str1-$str2-$str3
else
    echo "do nothing"
fi

Pass a string as parameter

Jasmitha Meka
  • 1,387
  • 3
  • 10
  • 11
1

No pipes, no forks, no cutting, no awking, just plain POSIX shell:

$ s=1001.2001.3001.5001.6001
$ oldIFS=$IFS
$ IFS=.-
$ set -- $s
$ case $s in
> (*.*) echo "$1.$2.$3.$(($4 + 121)).$5";;
> (*-*) echo "$1-$2-$3-$(($4 + 121))-$5";;
> esac
1001.2001.3001.5122.6001
$ IFS=$oldIFS
Jens
  • 69,818
  • 15
  • 125
  • 179
  • Why the downvote? If there's anything wrong, please give me a chance for improvement. – Jens May 14 '17 at 20:57
0

One liner

value=121 ; str='1001.2001.3001.5001.6001' ; token="$(echo "$str" | cut -f 4 -d '.')" ; newtoken=$(( $token + $value )) ; newstr="$(echo "$str" | sed -e "s/$token/$newtoken/g" | tr '.' '-')" ; echo "$newstr"

Breakdown:

value=121                                            # <- Increment
str='1001.2001.3001.5001.6001'                       # <- Initial String
token="$(echo "$str" | cut -f 4 -d '.')"             # <- Extract the 4th field with . sep
newtoken=$(( $token + $value ))                      # <- Add value and save to $newtoken
newstr="$(echo "$str" \
| sed -e "s/$token/$newtoken/g" \
| tr '.' '-')"                                       # <- Replace 4th field with $newtoken
                                                     #    and translate "." to "-"
echo "$newstr"                                       # <- Echo new string

Works in:

  • Bash
  • sh
  • FreeBSD
  • Busybox

Using out of the box tools

Community
  • 1
  • 1
hmedia1
  • 5,552
  • 2
  • 22
  • 27
-1

If the field separator can either be . or -, then do something like

echo "1001.2001.3001.5001.6001" | awk 'BEGIN{FS="[.-]";OFS="-"}{$4+=121}1'
1001-2001-3001-5122-6001

However, if you need to match the regex FS or field separator with OFS then you need to have gawk installed

echo "1001.2001.3001.5001.6001" |
gawk 'BEGIN{FS="[.-]"}{split($0,a,FS,seps)}{$4+=121;OFS=seps[1]}1'
1001.2001.3001.5122.6001
sjsam
  • 21,411
  • 5
  • 55
  • 102
  • @hmedia1 shame?? Why don't you consider this as a possible solution? And I have not even claimed this to be the best solution. – sjsam May 14 '17 at 16:01
-1

Though resetting the argument list with the values is probably the preferred way, or by setting IFS to the delimiter and reading the values into an array and adding the desired value to the array index at issue, you can also do it with a simple loop to look for the delimiters and continually skipping characters until the desired segment is found (4 in you case -- when the delimiter count is 3). Then simply appending the digit at each array index until your next delimiter is found will give you the base value. Simply adding your desired 121 to the completed number completes the script, e.g.

#!/bin/bash

str=${1:-"1001.2001.3001.5001.6001"}    ## string
ele=${2:-4}     ## element to add value to [1, 2, 3, ...]
add=${3:-121}   ## value to add to element
cnt=0           ## flag to track delimiters found
num=

## for each character in str
for ((i = 0; i < ${#str}; i++))
do
    if [ "${str:$i:1}" = '.' -o "${str:$i:1}" = '-' ]   ## is it '.' or '-'
    then
        (( cnt++ ))                 ## increment count
        (( cnt == ele )) && break   ## if equal to ele, break

    ## check each char is a valid digit 0-9
    elif [ "0" -le "${str:$i:1}" -a "${str:$4i:1}" -le "9" ]
    then
        (( cnt == (ele - 1) )) || continue  ## it not one of interest, continue
        num="$num${str:$i:1}"               ## append digit to num
    fi
done

((num += add))  ## add the amount to num

printf "num: %d\n" $num     ## print results

Example Use/Output

$ bash parsenum.sh
num: 5122

$ bash parsenum.sh "1001.2001.3001.5001.6001" 2
num: 2122

$ bash parsenum.sh "1001.2001.3001.5001.6001" 2 221
num: 2222

Look things over and let me know if you have any questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85