2

Please see the below session transcript:

$ mkdir temp
$ cd temp/
$ touch file{1..5}
$ ls
file1  file2  file3  file4  file5
$ SRC=file; TGT=ram
$ for f in file* ; do mv $f ${f/$SRC/$TGT} ; done
$ ls
ram1  ram2  ram3  ram4  ram5
$ PAT=ram/file
$ for f in ram* ; do mv $f ${f/$PAT} ; done
mv: 'ram1' and 'ram1' are the same file
mv: 'ram2' and 'ram2' are the same file
mv: 'ram3' and 'ram3' are the same file
mv: 'ram4' and 'ram4' are the same file
mv: 'ram5' and 'ram5' are the same file

Why does the pattern substitution work if I provide SRC and TGT as separate variables and not if I provide them as a single variable PAT?

My understanding is that substitutions are processed inside out, and so the string within the outer set of braces i.e. f/$SRC/$TGT or f/$PAT should be equally processed to f/file/ram or f/ram/file, which is then again processed to give the actual new file name. But apparently this is not done so…

I'm using Bash 4.4.18 on Kubuntu Bionic LTS with latest updates.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
jamadagni
  • 1,331

1 Answers1

3

From the Bash manual:

${parameter/pattern/string}
The pattern is expanded to produce a pattern just as in filename expansion. [...] If string is null, matches of pattern are deleted and the / following pattern may be omitted.

So, the process isn't such that the pattern and replacement are determined after expansion. Instead, first the pattern and replacement components are identified, and then they're expanded. In ${f/$PAT}, the entirety of $PAT becomes the pattern, and the replacement is empty.

muru
  • 72,889
  • You can use eval to work around that: eval "mv \$f \${f/$PAT}". Would be great to include this (or other possible solutions) in your answer. – filbranden Jun 06 '19 at 13:02
  • 1
    @filbranden Using eval safely is tricky enough that I'd rather not. This is pretty much a non-problem - I don't see any good reason why anyone would want to do this. Even if, for some weird reason, somebody had pattern/string in a variable, splitting those out into separate variables is easy enough that there's no good reason to use eval either. – muru Jun 06 '19 at 13:38