LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   substr using start-end position? (https://www.linuxquestions.org/questions/programming-9/substr-using-start-end-position-934460/)

saeedamer 03-14-2012 02:26 PM

substr using start-end position?
 
Hi there

I am not shell scripting expert. I want to extract a substring out of a string starting at a particular position and ending at particular position. The string is a directory path and I want to extract a certain part of this directory path (as substring).

So for example if I have following directory:

Code:

/su01/app/oracle/admin/testdb/bdump
I want to extract "testdb" out of the above path. The "/su01/app/oracle/admin/" part of the path will always be same. The "testdb" will change and "/bdump" will always be the same.

This is how I am trying to do this:

Code:

for lin in `find /su01 -name "bdump" -print 2>/dev/null `
  do
    echo $lin
    st=`echo $lin | awk '{print match($0, "admin")}'`
    en=`echo $lin | awk '{print match($0, "bdump")}'`
    db=`echo $lin | nawk '{print substr($lin,$st+6,$en-1)}'`
    echo $db
    echo $st
    echo $en
  done

Looks like substr will not allow me to specify the START position and END position. Can this be done in any other way?

Please advise!

colucix 03-14-2012 02:49 PM

Actually the substr function in awk requires the string, the start and the length of the string, not the ending position, hence you have to compute the length of the string by subtraction. Anyway, why not using the dirname and basename commands? Example:
Code:

$ basename `dirname /su01/app/oracle/admin/testdb/bdump`
testdb

Hope this helps.

whizje 03-14-2012 03:33 PM

${string#substring} removes shortest substring from front of string
${string%%substring} removes longest substring from end of string
Code:

str='/su01/app/oracle/admin/testdb/bdump';str=${str#*admin/};echo ${str%%/*}
testd


danielbmartin 03-14-2012 03:59 PM

There are lots of ways to do this.
Here is another: reverse, cut, reverse.
Code:

echo "/su01/app/oracle/admin/testdb/bdump" |rev |cut -d/ -f2 |rev
Daniel B. Martin

adixon 03-14-2012 10:09 PM

can also change the delimiters awk uses

Code:

.
.
db=`echo $lin | awk --field-separator="/" '{print $6)}'`
echo $db
.
.


grail 03-15-2012 02:32 AM

May I also suggest that you look at the man page for find as you could get it to return:
Code:

/su01/app/oracle/admin/testdb

Reuti 03-15-2012 05:12 AM

Quote:

Originally Posted by saeedamer (Post 4626786)
Code:

for lin in `find /su01 -name "bdump" -print 2>/dev/null `
  do
    echo $lin
    st=`echo $lin | awk '{print match($0, "admin")}'`
    en=`echo $lin | awk '{print match($0, "bdump")}'`
    db=`echo $lin | nawk '{print substr($lin,$st+6,$en-1)}'`
    echo $db
    echo $st
    echo $en
  done


Besides all the suggestions to get the result, I would like to mention for the above sequence: the environment variables won’t be known inside the awk script. It’s either necessary to use proper quoting or make them known inside awk by the -v option:
Code:

db=`echo $lin | awk -v st=$st -v en=$en '{print substr($0,st+6,en-st-7)}'`
And then it could be put in one statement to read:
Code:

db=`echo $lin | awk '{st=match($0, "admin"); en=match($0, "bdump"); print substr($0,st+6,en-st-7)}'`

saeedamer 03-15-2012 06:40 AM

Thank you so so much everyone!!!

Reuti 03-15-2012 07:37 AM

NB: If you expect the results only in /su01/app/oracle/admin, it would be good to use it as start directory in the find command as it will return faster (assuming there is more in /su01 besides the files in question). Then find can be tuned to output “testdb/bdump”. It’s a matter of taste, whether to remove the leading part like with Grails suggestion, or the trailing one.

It’s a pitty, that -printf will only change the output, but not the string used for {} in -exec, so you need xargs in addition. Maybe -setf would be an RFE.

David the H. 03-15-2012 02:39 PM

See here for lots of bash string manipulation techniques:

http://mywiki.wooledge.org/BashFAQ/100

One of the best options in this situation is to load the path into an array, splitting the string by "/", of course.

Code:

$ IFS='/' read -a path <<<'/su01/app/oracle/admin/testdb/bdump'

$ echo "${path[1]}" "${path[3]}" "${path[5]}"
su01 oracle testdb


(P.S. If you're wondering why the array appears to not be zero-based, note that if IFS is set to a non-space value, the empty string in front of a leading delimiter is read as element "0".)


All times are GMT -5. The time now is 01:42 PM.