rename files: delete name up to first underscore

47 Views Asked by At

I have several thousand files that need to be renamed. They are in the form of xxxxx_file name.doc

The xxxx is alpha-numeric but in all cases the prefix upto and including the first underscore needs to be removed if possible. There will be some files that will end up with duplicate names so it is important that any duplicates don't overwrite an existing file (they should be ignored).

If there is no underscore, it should be skipped.

examples:
3445sh0_may_receipts.doc
df784hb68_sample.file-name.doc
b6890zs22_sample file name.doc
b6890zs22_sample_name.doc
gh7856n77.doc
56n57swd0.doc
etc ...

I am not skilled in the use of awk, but it seems that awk might be used with the underscore as a delimiter and the first column up to the first underscore ignored. I don't know what awk would do if a duplicate file is found.

4

There are 4 best solutions below

1
karakfa On BEST ANSWER

improving on @dawg's anser

for fn in *_*; do
    if [[ ! -f "${fn#*_}" ]]
    then 
       mv -i "$fn" "${fn#*_}"
    fi
done 

don't move if the file exists, and as an additional protection, prompt for overwrite.

0
dawg On

Suppose you have these files:

$ ls -1
3445sh0_may_receipts.doc
b6890zs22_sample file name.doc
b6890zs22_sample_name.doc
df784hb68_sample.file-name.doc
gh7856n77.doc

You can:

  1. Use a glob to skip the files without _ in the names;
  2. Use parameter expansion to remove the leading part xxxx_;
  3. Rename the files based on that.

So:

for fn in *_*; do
    mv "$fn" "${fn#*_}" 
done   

Results in:

$ ls -1
gh7856n77.doc
may_receipts.doc
sample file name.doc
sample.file-name.doc
sample_name.doc

Know that if removing the xxx_ part results in a file name that is already existing, the previous file will be overwritten silently...

1
Daweo On

As far as I know GNU AWK has not function or tool rename file thus you would need delegate that to other thing or use tool which does support. If you must use GNU AWK AT ANY PRICE then I suggest to create bash script and then execute if as follows, let say you have file.txt holding

3445sh0_may_receipts.doc
df784hb68_sample.file-name.doc
b6890zs22_sample file name.doc
b6890zs22_sample_name.doc
gh7856n77.doc
56n57swd0.doc

then

awk 'BEGIN{FS=OFS="_"}NF>1{oldname=$0;$1="";newname=substr($0,2);print "mv --no-clobber \047" oldname "\047 \047" newname "\047"}' file.txt > renamefiles.sh

creates renamefiles.sh with following content

mv --no-clobber '3445sh0_may_receipts.doc' 'may_receipts.doc'
mv --no-clobber 'df784hb68_sample.file-name.doc' 'sample.file-name.doc'
mv --no-clobber 'b6890zs22_sample file name.doc' 'sample file name.doc'
mv --no-clobber 'b6890zs22_sample_name.doc' 'sample_name.doc'

which you might then use with bash following way

bash renamefiles.sh

Explanation: I inform GNU AWK that underscore is both field separator (FS) and output field separator (OFS) then for line with more than 1 field I save whole line as oldname, clear 1st field and get substring starting at 2nd character (as 1st is now underscore) then I print mv command with --no-clobber flag to prevent overwrite. Note that I enclose names in quotes or in GNU AWK language \047 characters, to counterbalance names holding space. Disclaimer: generate name might malfunction if there is name with ' character or newline character in it.

(tested in GNU Awk 5.1.0)

0
ghoti On

The pattern is different so it's perhaps not exactly a duplicate question, but similar things have been asked before.

If you are using Linux, look for the rename command. A couple of different versions exist. Your distro (Debian maybe?) may ship with a Perl /usr/bin/rename (or prename) that works like this:

rename "s/pattern1/pattern2/" glob*

Think of the first option as you would a sed substitution (though it's actually a Perl expression). For example,

rename "s/^[^_]+_//" *_*.doc

Alternately, you may have a version (from RHEL or CentOS for example) that takes options like this:

rename pattern1 pattern2 pattern1.*

Check your man page for details.