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 '16 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 '16 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 '16 at 19:26

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 '16 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 '16 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 '16 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 '16 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 '16 at 19:27

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.