1

Trying to extract some parts of a string into variables. Initial string looks like this: /dev/sdc2: LABEL="PAKAGE" UUID="9501DCBF768CEBB9" TYPE="ntfs" I getting correct PORT and LABEL values, but cant get the rest: UUID and TYPE. Instead of them I getting just a piece of it.

#!/bin/bash

INDEX1=""
INDEX2=""
LENGTH=""
PORT=""
LABEL=""
UUID=""
TYPE=""

line=`echo /dev/sdc2: LABEL="PAKAGE" UUID="9501DCBF768CEBB9" TYPE="ntfs" | sed s/\"//g`
echo $line

INDEX1=`expr index "$line" /dev/`
PORT=${line:$INDEX1-1:9}

INDEX1=`expr index "$line" LABEL=`
INDEX2=`expr index "$line" UUID`
INDEX1=`expr $INDEX1 + 5`
INDEX2=`expr $INDEX2 - 2`
LABEL=${line:$INDEX1:$INDEX2-$INDEX1}

INDEX1=`expr index "$line" UUID=`
INDEX2=`expr index "$line" TYPE`
INDEX1=`expr $INDEX1 + 4`
INDEX2=`expr $INDEX2 - 2`
UUID=${line:$INDEX1:$INDEX2-$INDEX1}

INDEX1=`expr index "$line" TYPE=`
INDEX1=`expr $INDEX1 + 4`
TYPE=${line:$INDEX1}

echo $PORT
echo $LABEL
echo $UUID
echo $TYPE


Here the output of this script:
/dev/sdc2: LABEL=PAKAGE UUID=9501DCBF768CEBB9 TYPE=ntfs
/dev/sdc2
PAKAGE
GE UUID=9501DCBF768CEBB9 T
KAGE UUID=9501DCBF768CEBB9 TYPE=ntfs

Where am I wrong?

2
  • 1
    It would be better/safer to not do this in bash at all: The Python shlex module (in the standard library) is a better lexer for shell syntax than anything bash has available built-in. Otherwise, you end up with approaches that either are dangerous (as with eval) or fragile (as with trying to roll your own parser). Commented Sep 27, 2013 at 20:15
  • I do not know python unfortunately (as well as regexp) Commented Sep 27, 2013 at 21:41

5 Answers 5

3

I think it's better done with regexp.

#!/bin/bash
src='/dev/sdc2: LABEL="PAKAGE" UUID="9501DCBF768CEBB9" TYPE="ntfs"'

regex='([^:]+): LABEL="([^"]+)" UUID="([^"]+)" TYPE="([^"]+)"'

if [[ $src =~ $regex ]]; then
    echo "matches"
    i=1
    n=${#BASH_REMATCH[*]}
    while [[ $i -lt $n ]]
    do
        echo "  capture[$i]: ${BASH_REMATCH[$i]}"
        let i++
    done
else
    echo "does not match"
fi

Output:

 matches
  capture[1]: /dev/sdc2
  capture[2]: PAKAGE
  capture[3]: 9501DCBF768CEBB9
  capture[4]: ntfs

Based on this.

Sign up to request clarification or add additional context in comments.

2 Comments

A more generic regex would be regex='([^:]+): LABEL="([^"]+)" UUID="([^"]+)" TYPE="([^"]+)"' -- that does not assume anything about the values of the variables
I do not think its possible with regexp due to different delimiters. But it really works just fine. Many thanks!
1

This uses eval and is therefore risky. Ensure you know where your data is coming from.

$ line='/dev/sdc2: LABEL="this is the label" UUID="this is the uuid" TYPE="ntfs"'
$ IFS=: read port variables <<< "$line"
$ echo "$port"
/dev/sdc2
$ echo "$variables"
 LABEL="this is the label" UUID="this is the uuid" TYPE="ntfs"
$ eval "$variables"
$ printf "%s='%s'\n" label "$LABEL" uuid "$UUID" type "$TYPE"
label='this is the label'
uuid='this is the uuid'
type='ntfs'

Comments

1

Defining patterns over values, instead of keys, isn't the best way to deal with parsing. You might be better off doing it this way:

$ line='/dev/sdc2: LABEL="PAKAGE" UUID="9501DCBF768CEBB9" TYPE="ntfs"'
$ entry=( ${line//\"/} )

$ PORT=${entry[0]} PORT=${PORT//:/}     # defining variable PORT
$ declare ${entry[1]}                   # defining variable LABEL
$ declare ${entry[2]}                   # defining variable UUID
$ declare ${entry[3]}                   # defining variable TYPE    

$ echo -e "${PORT}\n${LABEL}\n${UUID}\n${TYPE}"
sdc2:
PAKAGE
9501DCBF768CEBB9
ntfs

2 Comments

@1_CR Mis-reverse-engineered the OP's example (: Thanks for pointing it out!
You're assuming there's no whitespace in the quoted values.
0

You could resort to simply clearing the string of all the undesirable portions and using read to populate your variables

read -r PORT LABEL UUID TYPE <<< "$(echo '/dev/sdc2: LABEL="PAKAGE" UUID="9501DCBF768CEBB9" TYPE="ntfs"' |\
sed 's/\(.*\): \+LABEL="\([^"]\+\)" \+UUID="\([^"]\+\)" \+TYPE="\([^"]\+\)"/\1 \2 \3 \4/')"
echo $PORT
/dev/sdc2
echo $LABEL
PAKAGE
echo $UUID
9501DCBF768CEBB9
echo $TYPE
ntfs

2 Comments

You are assuming there is no whitespace in any of the variable values.
@glennjackman, you're right. I actually like your eval solution better
0

Without eval, but same logic using :

$ line=\"/dev/sdc2: LABEL="PAKAGE" UUID="9501DCBF768CEBB9" TYPE="ntfs"\"
$ echo "${line%% *}"
/dev/sdc2
$ echo "$LABEL"
PAKAGE
$ echo "$UUID"
9501DCBF768CEBB9
$ echo "$TYPE"
ntfs

2 Comments

I don't get that output: I see "/dev/sdc2: and ntfs"
Added bash requirement.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.