Vituvo
Vituvo

Reputation: 1048

How to rename multiple files with similar strings separated by periods and underscores with the rename command

Ubuntu 16.04
Bash 4.4.20
Rename 0.20

I have hundreds of files that get copied to a folder each day. The folder name is different each day so the files on the inside of the folder have to be renamed

Here is an example of the files after being copied to the folder.

2019-11-30_hs5_felix.doggie.com_1112.garage
2019-12-01_hs5_ralph.doggie.com_1112.garage
2019-12-04_hs5_sartah.doggie.com_1112.garage
2019-12-05_hs5_felix.doggie.com_1112.garage
2019-12-07_hs5_ggg.doggie.com_1112.garage
2019-12-12_hs5_fex.doggie.com_1112.garage
2019-12-19_hs5_sioia.doggie.com_9999.garage
2019-12-21_hs5_felix.doggie.com_1002.garage
2019-12-22_hs5_sonia.doggie.com_1112.garage
2019-12-25_hs5_isabel.doggie.com_1106.garage  

Here is the pattern that will be the same:

same_same_"${one}".same.same_"${two}".same

So the variables will represent two words we will use to rename all the files to and the files need to look like the following after being renamed:

one="ssss"
two="1234"

2019-11-30_hs5_sssss.doggie.com_1234.garage
2019-12-01_hs5_sssss.doggie.com_1234.garage
2019-12-04_hs5_sssss.doggie.com_1234.garage
2019-12-05_hs5_sssss.doggie.com_1234.garage
2019-12-07_hs5_sssss.doggie.com_1234.garage
2019-12-12_hs5_sssss.doggie.com_1234.garage
2019-12-19_hs5_sssss.doggie.com_1234.garage
2019-12-21_hs5_sssss.doggie.com_1234.garage
2019-12-22_hs5_sssss.doggie.com_1234.garage
2019-12-25_hs5_sssss.doggie.com_1234.garage

The final product is more important than how it is done so we can use any commands to get there.

Upvotes: 1

Views: 234

Answers (4)

potong
potong

Reputation: 58400

This also may work for you - (GNU parallel):

parallel 'mv {1} {=1 s/(_.*_)[^.]+(.*_)[^.]+/$1$arg[2]$2$arg[3]/ =}' ::: * ::: ssss ::: 1234

Use GNU parallel to eliminate forloop and shell variables. The {=n ... =} allows the use of perl commands on the n'th positional replacement string. In this case, use the substitution command to replace parts of each file name garnered from ::: *.

Note: Before executing this command, it is always good practice to insert the --dry-run option and inspect its output before running it live.

Upvotes: 2

Ivan
Ivan

Reputation: 7277

i came out with this for your filenames(2019-12-19_hs5_sioia.doggie.com_9999.garage)

one="ssss"
two="1234"

for file in *; { name=${file//_[0-9]*.g/_$two.g}; name=${name//_*.d/_$one.d}; mv $file $name; }

This method uses variable substitutions ${var//pattern/change}

Upvotes: 1

tshiono
tshiono

Reputation: 22012

According to the pattern same_same_"${one}".same.same_"${two}".same, how about:

one="ssss"
two="1234"
for f in *.*; do
    IFS=_ read -ra a <<< "$f"
    a[2]="${one}.${a[2]#*.}"
    a[3]="${two}.${a[3]#*.}"
    (IFS=_; mv -- "$f" "${a[*]}")
done

It first splits the filename on _, replaces the specified positions with the variables, then merges them again as a new filename.

Upvotes: 2

David C. Rankin
David C. Rankin

Reputation: 84561

Without rename, you can actually change the names of the files making both substitutions of "$one" and "$two" using the mv command and a command-substitution using sed. This eliminates the "Which version of rename do I have?"

For example, in your case, you can change to the directory containing the files, and do:

one="ssss"
two="1234"

for i in *; do 
    mv "$i" "$(sed 's/^\(.*hs5_\)[^.]*\([.].*com_\)[0-9]*\(.*$\)/\1'"$one"'\2'"$two"'\3/' <<< "$i")"
done

Which makes use of sed normal substitution command making use of three-capture groups and backreferences.

Explanation

The sed substitution command is sed 's/find/replace/' where in your case the find is broken into the parts:

  • ^\(.*hs5_\) match from the beginning of the filename through "hs5_" capturing the text within a capture group of \( ... \) using basic regular expressions to be reinserted with the first backreference \1;
  • from "hs5_" on we match [^.]* a sequence of characters not containing a '.';
  • we then capture from the '.' through "com_" capturing \([.].*com_\) to reinsert with the second backreference \2; and finally
  • capture all characters to the end of the filename with \(.*$\) for reinsertion as \3

For the replace portion, we just include the captured text making the variable substitutions:

  • \1'"$one"'\2'"$two"'\3

(note: the quoting is very specific. The parts of the sed command are enclosed in single quotes which the shell variables are enclosed in double quotes, along with the complete command substitution.

The basic move of the file in accomplished with mv "$i" "$(sed ... <<< "$i") where the filename is fed to the sed command using a bash-only Here-String <<< which redirects the contents of the variable to the sed command on stdin allowing sed to make the substitutions completing the move.

Upvotes: 2

Related Questions