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.

4
  • Thanks to show us a concrete example Commented Jan 18, 2023 at 16:59
  • How is the variable written in the file? Is the file in a structured document format such as XML or JSON?
    – Kusalananda
    Commented Jan 18, 2023 at 17:10
  • What operating system are you using? What do you mean by "bash scripting only"? Does that mean no external tools at all? No sed, no rename, no mv?
    – terdon
    Commented Jan 18, 2023 at 17:15
  • I am using cygwin
    – tabi
    Commented Jan 18, 2023 at 18:00

3 Answers 3

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.

1
  • 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
    Commented Jan 18, 2023 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##*_}"

You must log in to answer this question.

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