2

I have a directory in the following format:

/folder1/folder2/name_X_Y_Z_A

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 – steeldriver 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? – sodiumnitrate Aug 5 '16 at 19:26
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.

newdir="/folder1/folder2/name_$((${arr[1]}-1))_${arr[3]}_Z_A"

[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]}? – sodiumnitrate 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 – steeldriver 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? – sodiumnitrate 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))" – steeldriver Aug 5 '16 at 20:36
3

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

eg

# DIR=$PWD
# example:
DIR=/folder1/folder2/name_100_YYYY_ZZZZ_AAAA

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

let X=X-1
DIR="${DIR}_${X}_${Y}_${Z}_${A}"

echo $DIR

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

# DIR=$PWD
# example:
DIR=/folder1/folder2/name_100_YYYY_ZZZZ_AAAA

DIRX=${DIR%_*_*_*}

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

let X=X-1
DIR="${DIRX}_${X}${YZA}"

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.

2

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
name_11_ABCD_ABC_ABCD
  • Thanks for the answer! It's good to know I can do this, but I'd rather rely on bash only. – sodiumnitrate 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.