bash - Batch rename files that do not match pattern

01
2014-07
  • Atul Kakrana

    I do not have programming experience and mostly use one-liner or sometimes more to get the job done. I am having problem to batch rename the files that do not match a particular pattern.

    Sample file-names from directory:

    Meeting_Packages.pdf
    13_textfile0
    19_textfile0
    23_textfile0
    29_textfile0
    33_textfile1
    45_textfile0
    5_textfile3
    Membership.pdf
    13_textfile1
    19_textfile1
    23_textfile1
    29_textfile1
    34_textfile0
    46_textfile0
    6_textfile0
    xyz2009.pdf
    13_textfile2
    19_textfile2
    23_textfile2
    29_textfile2
    34_textfile1
    47_textfile0
    6_textfile1
    meeting.ics
    

    I want to rename the files e.g. Meeting_Packages.pdf, Membership.pdf, meeting.ics and xyz2009.pdf to the file from where they came (input file). Actually it is output of ripmime with mails as xx_textfilex and others are attachments. I want to name attachments as the original input file

    My Code:

    #!/bin/bash
    
    FILES=*.mime
    for f in $FILES
    do
        echo "Processing $f"
        #rip mails into attachments and text files also add a prefix to text files
        ripmime -i $f -d ~/test/ripmime --prefix 
        #Remove white spaces from files 
        rename 's/ /_/g' ~/test/ripmime/*
        #rename attachments as original input files
        rename 's/\[^0-9]/'$f/ ~/test/ripmime/* 
    done
    

    My problem is the last rename line where I try to filter files other than xx_textfilex and rename. I tried different regular expressions but could not do that. I can select and rename the textfiles by:

    rename 's/textfiles/'$f/ ~/test/ripmime/*
    

    but I need the inverse of that and rename files other then textfiles.

    How can I do this?

  • Answers
  • Simon Sheehan

    I use https://gist.github.com/995151

    rename 's/\.bak$//' *.pdf

  • Darthenius

    You can combine ls and grep -v:

    ls | grep -v ".*textfile.*" | while read filename; do
      # rename $filename to something
    done
    

  • Related Question

    How can I batch rename files in bash?
  • Nathan Long

    I've got some files like this:

    database1-backup-01-01-2011.sql
    database2-backup-01-01-2011.sql
    

    ...etc. I want to rename them to add AM, like this:

    database1-backup-01-01-2011-AM.sql
    database2-backup-01-01-2011-AM.sql
    

    What's the most concise way to do that from the bash shell?


  • Related Answers
  • chrish

    Another option:

    for i in *.sql ; do
        mv -v $i ${i%.sql}-AM.sql
    done
    

    This loops through all the .sql files and renames them to end in -AM.sql instead.

    PROTIP: Use $(command) instead of `command` in your scripts (and command-lines), it makes quoting and escaping less of a nightmare.

  • Majenko

    Try this little script:

    #!/bin/sh
    
    FILES=`ls *.sql`
    for FILE in ${FILES}
    {
        BASE=`basename ${FILE} .sql`
        mv ${FILE} ${BASE}-AM.sql
    }
    

    I just typed that from memory so if it doesn't work 100% don't blame me (i.e., back up your data first ;) )

    How it works:

    Collect all files into a variable (you could put this inside the for instead but I like to keep things easy to read):

    FILES=`ls *.sql`
    

    Loop through each file:

    for FILE in ${FILES} { ... }
    

    Get the filename without .sql:

    BASE=`basename ${FILE} .sql`
    

    Rename the file, adding -AM.sql to the base name:

    mv ${FILE} ${BASE}-AM.sql
    
  • Dennis Williamson

    Using the Perl script version of rename:

    rename 's/\.sql$/-AM$&/' *.sql
    

    Using the util-linux-ng version of rename (but only if ".sql" only appears at the end of the filename):

    rename .sql -AM.sql *.sql
    

    Using mmv:

    mmv '*.sql' '#1-AM.sql'
    
  • Nathan Long

    Since a Perl script has been suggested, here's a Ruby script to do the same:

    `ls *.sql`.split("\n").each do |filename|
      new_filename = filename.split('.').join('-AM.')
      `mv #{filename} #{new_filename}`
    end