1

I have a two part question.

I have a series of files with the names "file.pdb.#", where # is an integer.

1.) How can I script to rename all the "file.pdb.#" to "file_#.pdb", where the integer is preserved? All files are in the same directory.

I presumably need to read in the constant string (file.pdb.) with the variable being the #.

2.) Even more important, how would I have searched for this answer, properly, among answered questions? I have no doubt this question has been answered many times before. However, I am not sure how I might have properly searched for the answer to this question (and obviously I should learn to search previously answered questions better to not bother people in the future). I cannot imagine what the right search string is (googling how to read in files and rename them in Linux is awfully generic and I waded through suggestions not germane to this sort of file format manipulation).

2
  • 3
    Your 2nd part needs to be a different question on meta; not on AU. Please remove it and re-ask.
    – Rinzwind
    Jul 2, 2015 at 3:30
  • Answer for first question mmv file.pdb.* file_#1.pdb Jul 2, 2015 at 3:47

3 Answers 3

7

You can use capture groups and backreferences e.g.

rename -vn -- 's/\.(pdb)\.(\d+)/_$2.$1/' *.pdb.*

to match a literal period \. followed by (literal) string pdb, followed by a second period \. and then a sequence of one or more digits \d+, copying the string and digit sequence into numbered capture groups $1 and $2 respectively and then re-substituting them in reverse order with an underscore in place of the first period.

Options -v and -n are for verbose output (listing any changes made) and no-operation, allowing you to test the correctness before committing to making any actual substitutions: you will need to remove the n option to actually apply the changes.

The -- marks the end of command options - this just makes the command more robust in the rare case that you have filenames that start with a hyphen.


Testing it in a directory containing files file.pdb.1 file.pdb.2 file.pdb.3 file.pdb.4 file.pdb.5 (among others):

$ rename -vn -- 's/\.(pdb)\.(\d+)/_$2.$1/' *.pdb.*
file.pdb.1 renamed as file_1.pdb
file.pdb.2 renamed as file_2.pdb
file.pdb.3 renamed as file_3.pdb
file.pdb.4 renamed as file_4.pdb
file.pdb.5 renamed as file_5.pdb
6
  • Can you explain the logic of the syntax a bit? The string did not work, when blindly copy/pasting it, such that there is a flaw in how I explained things that this did not work. I would like to understand what this says better. Jul 2, 2015 at 23:59
  • @RobertMolt please see updated answer Jul 3, 2015 at 0:22
  • I appreciate your efforts very much. There still seems to be a flaw; when implemented, with or without the n flag, there is no output. If you were to make two files in a directory named file.pdb.1 and file.pdb.2, and implemented the above, do you see the desired results? You have explained everything beautifully, and I appreciate it. I assume .pdb. at the end simply clarifies on what set of files one should implement the aforementioned substitution. Jul 4, 2015 at 22:23
  • @RobertMolt sorry I don't understand why it is not working for you: I have edited my answer to include the result of testing on my own system. Jul 4, 2015 at 22:35
  • I appreciate your sincere efforts; clearly it works for you. Is the command shell-dependent? I am using bash. I am desperately reaching here trying to understand why this is not recognizing any of my files with the same names are causing this. I am running this on Red Hat linux, but I cannot imagine this should matter (I personally own a Ubuntu OS, but am doing this on a Red Hat flavor). Jul 4, 2015 at 23:08
1

The strictest way possible, so that only filenames starting with file.pdb. followed by at least a digit will be renamed, using rename:

rename -n 's/(file)(\.pdb)\.([0-9]+)/$1_$3$2/' *

If the result is the expected one, remove the -n option:

rename 's/(file)(\.pdb)\.([0-9]+)/$1_$3$2/' *
1

Apart from excellent rename answers you have received already, you can use bash parameter expansion:

for i in *.pdb.*; do mv -i "$i" "${i%%.pdb.*}_${i##*.}.pdb"; done
  • The pattern ${i%%.pdb*} will get the file portion of name file.pdb.#

  • ${i##*.} will get the digits after .pdb.

2
  • Thank you, this suggestion worked (whereas the others did not for some reason). I was hoping to ask a bit more to understand it properly. -i seems like an implicit variable which is a string -"${i%%.pdb.*} how is %% specifying the file portion? can you direct me to where I can understand why this syntax is grabbing the file name preceding .pdb? -what is the underscore doing? -how does ## read in the correct digits? I tend to think of things in Fortran, my only real programming experience, and hence I am confused. Jul 2, 2015 at 23:30
  • @RobertMolt i have taken the variables as variable i, then renamed them by using parameter expansion..its a feature of bash that will allow you to manipulate variables to get your desired portion (and many more operations)..i am afraid to get a full grasp off of it you need to get some idea about it first....you can read this..check out the ${parameter##word} and ${parameter%%word} portions
    – heemayl
    Jul 2, 2015 at 23:36

You must log in to answer this question.

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