I have a directory in the following format:


where X is a number, Y, Z, and A are 3 or 4 character long strings.

I want to write a shell script file that does the following:

  • extract X and Z from the folder name
  • create the string /folder1/folder2/name_(X-1)_Y_Z_A
  • copy the file string_Z.dat from that directory

I'm lost as to how to extract specific patterns from $PWD. The character positions of X and Z don't have to be the same, as the number length and the length of name can vary.

  • the key point being that the last element of the directory has those pieces separated by underscores?
    – Jeff Schaller
    Aug 5, 2016 at 19:08
  • 2
    Something like IFS=_ read -a arr <<< "${PWD##*/}" maybe? then use ${arr[1]} and ${arr[3]} to build the new name Aug 5, 2016 at 19:19
  • @steeldriver yes, that works perfectly! Thanks :) Can you post this as an answer? Also, how can I get the number right before the first underscore? Aug 5, 2016 at 19:26

3 Answers 3


You can first trim the leading path components using the shell's parameter substitution syntax ${PWD##*/}, then read the basename into an array using underscores as a field separator:

IFS=_ read -a arr <<< "${PWD##*/}"

Since bash arrays are zero-indexed, the parts you want should be in ${arr[1]} and ${arr[3]} e.g.


[Note: I have assumed that you mean the arithmetic result of (X-1) rather than the literal string.]

  • Just curious: if it was nameX instead of name_X, is there a way to get the last two characters of ${arr[1]}? Aug 5, 2016 at 19:44
  • 1
    @sodiumnitrate in that case, name10 would be in the zeroth element, and you could extract the 2-character substring starting 2 chars from the end using "${arr[0]:(-2):2}" I think Aug 5, 2016 at 20:01
  • Thanks. When I do echo ${arr[0]:(-2):2}-1, the result is 12-1, not 11. What am I doing wrong? Aug 5, 2016 at 20:16
  • 1
    @sodiumnitrate to evaluate the expression arithmetically, you need to surround it with double parentheses $(( ... )) e.g. "$((${arr[0]:(-2):2}-1))" Aug 5, 2016 at 20:36

Assuming that X,Y,Z,A don't have any underscores in them then we can "cut off" the tail each time


# example:

A=${DIR##*_} ; DIR=${DIR%_*}
Z=${DIR##*_} ; DIR=${DIR%_*}
Y=${DIR##*_} ; DIR=${DIR%_*}
X=${DIR##*_} ; DIR=${DIR%_*}

let X=X-1

echo $DIR

The other way we can do this is to work out where X ends and strip off the rest in one go:

# example:


X=${DIRX##*_} ; DIRX=${DIRX%_*}

let X=X-1

echo $DIR

In both cases we get /folder1/folder2/name_99_YYYY_ZZZZ_AAAA as the result. You can easily cp your file into there.


If you can use python:

$ pwd=/folder1/folder1/name_10_ABCD_ABC_ABCD # or use $PWD
$ new=$(python -c "import os; x='"$pwd"'.rsplit('/', 1)[1].split('_'); x[1]=str(int(x[1])+1); print('_'.join(x))")
$ echo $new
  • Thanks for the answer! It's good to know I can do this, but I'd rather rely on bash only. Aug 5, 2016 at 19:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .