0

I have a set of files with the following filename structure:

aa_bbbbb_cccccccc_dddddd.txt

I want to replace the third element cccccccc with the value of the variable value which I extract from the content of the file.

The values of the 4 components of the filename change, so I cannot replace using string replacement, but I need to replace based on the position of the substring I want to replace.

Any suggestion how to approach this using bash script only?


I cannot use rename. It does not seem to work in cygwin and, in any case, I cannot use string replacement. If we consider the "_" as a separator, I need to replace the third field with the value contained in a variable.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
tabi
  • 11

3 Answers3

1

bash does have a splitting operator, the same awkward one as in ksh or in POSIX sh: the IFS-splitting that is performed (and most often unwanted) whem you leave a parameter expansion unquoted.

cmd $var

does split $var on $IFS characters (and also performs globbing), also known as the infamous split+glob operator.

Generally, you don't want that which is why you generally need cmd "$var", and even cmd -- "$var" for those commands that accept options.

However here, you could use it to do the splitting on _.

With:

IFS=_
set -o noglob
parts=( $file'' )

$file is being split on _ and the resulting parts stored in the $parts array¹.

Then you can do:

parts[2]=$value

To change the third part (in bash like in ksh but unlike most other shells, array elements indexes start at 0, so the 3rd element is in ${parts[2]}).

And you can join them pack with _s with:

newfile="${parts[*]}"
0

Example of a file with value variable

value=xxx

Then, using Perl's rename:

file=aa_bbbbb_cccccccc_dddddd.txt
rename -n 's/^(.+?_.+?)_.+?_(.*)/${1}_foo_$2/' ./"$file"

Remove -n (aka dry-run) when the output looks satisfactory.

  • The OP has said that "The values of the 4 components of the filename change, so I cannot replace using string replacement". They probably want something like rename -n 's/^(.+?_.+?)_.+?_(.*)/$1_foo_$2/' "$file". – terdon Jan 18 '23 at 17:21
0

Using Bash parameter expansion:

  • ${parameter##word} removes the longest matching prefix pattern word from parameter
  • ${parameter%word} removes the shortest matching suffix pattern word from parameter
file="aa_bbbbb_cccccccc_dddddd.txt"
value="replace me"

suffix=${file##} # dddddd.txt prefix=${file%} # aa_bbbbb_cccccccc prefix=${prefix%_*} # aa_bbbbb

mv "$file" "${prefix}${value}${suffix}"

or a bit shorter

file="aa_bbbbb_cccccccc_dddddd.txt"
value="replace me"
prefix=${file%_*}

mv "$file" "${prefix%*}${value}${file##*}"

Freddy
  • 25,565