33

https://serverfault.com/questions/70939/how-to-replace-a-text-string-in-multiple-files-in-linux

https://serverfault.com/questions/228733/how-to-rename-multiple-files-by-replacing-word-in-file-name

https://serverfault.com/questions/212153/replace-string-in-files-with-certain-file-extension

https://serverfault.com/questions/33158/searching-a-number-of-files-for-a-string-in-linux

These mentioned articles have all answered my question. However none of them work for me. I suspect it is because the string I am trying to replace has a # in it. Is there a special way to address this?

I have image file that had an é replaced by #U00a9 during a site migration. These look like this:

Lucky-#U00a9NBC-80x60.jpg
Lucky-#U00a9NBC-125x125.jpg
Lucky-#U00a9NBC-150x150.jpg
Lucky-#U00a9NBC-250x250.jpg
Lucky-#U00a9NBC-282x232.jpg
Lucky-#U00a9NBC-300x150.jpg
Lucky-#U00a9NBC-300x200.jpg
Lucky-#U00a9NBC-300x250.jpg
Lucky-#U00a9NBC-360x240.jpg
Lucky-#U00a9NBC-400x250.jpg
Lucky-#U00a9NBC-430x270.jpg
Lucky-#U00a9NBC-480x240.jpg
Lucky-#U00a9NBC-600x240.jpg
Lucky-#U00a9NBC-600x250.jpg
Lucky-#U00a9NBC.jpg

and I want to change it to something like this:

Lucky-safeNBC-80x60.jpg
Lucky-safeNBC-125x125.jpg
Lucky-safeNBC-150x150.jpg
Lucky-safeNBC-250x250.jpg
Lucky-safeNBC-282x232.jpg
Lucky-safeNBC-300x150.jpg
Lucky-safeNBC-300x200.jpg
Lucky-safeNBC-300x250.jpg
Lucky-safeNBC-360x240.jpg
Lucky-safeNBC-400x250.jpg
Lucky-safeNBC-430x270.jpg
Lucky-safeNBC-480x240.jpg
Lucky-safeNBC-600x240.jpg
Lucky-safeNBC-600x250.jpg
Lucky-safeNBC.jpg

UPDATE:

These examples all start with "LU00a9ucky but here are many images with different names. I am simply targeting the "#U00a9" portion of the string to replace with "safe".

migrated from serverfault.com Dec 20 '14 at 10:18

This question came from our site for system and network administrators.

  • 3
    So what have you actually tried? I see that you have linked to a few questions and say they failed, but how did they fail? IMO the best example uses the rename command. I suspect your rename would be as simple as rename -n 's/#/safeNBC/' *.jpg. – Zoredache Dec 19 '14 at 21:26
  • I tried rename -n 's/#U00a9/safe/' *.jpg and the command was accepted but no changes occurred. – Leon Francis Shelhamer Dec 19 '14 at 23:36
  • Sure, as you would have seen from the documentation you surely reviewed, the -n is the no act option. Which lets you see if it works before you actually use it. Did the output on the screen show the potential new names correctly? – Zoredache Dec 19 '14 at 23:55
  • I apologize I copied and pasted your example without paying full attention, I did the rename command without the -n. I believe @DTK address the problem, I was not escaping the #. – Leon Francis Shelhamer Dec 20 '14 at 8:17
  • Replacing strings in filenames on MacOS: superuser.com/questions/152627/… – Anton Tarasenko Nov 26 '18 at 10:07
51

To replace # by somethingelse for filenames in the current directory (not recursive) you can use the GNU rename utility:

rename  's/#/somethingelse/' *

Characters like - must be escaped with a \.

For your case, you would want to use

rename 's/#U00a9/safe/g' *

Note that if you only want to operate on a certain selection of files, e.g., only *.jpg, adjust the final input to match that selection:

rename 's/#U00a9/safe/g' *.jpg

To perform a test before actually changing filenames, use the -n flag:

demo/> ls                               
Lucky-#U00a9NBC-125x125.jpg  
Lucky-#U00a9NBC-150x150.jpg 

demo/> rename -n 's/#U00a9/safe/g' *.jpg
rename(Lucky-#U00a9NBC-125x125.jpg, Lucky-safeNBC-125x125.jpg)
rename(Lucky-#U00a9NBC-150x150.jpg, Lucky-safeNBC-150x150.jpg)

For OS X, GNU rename can be installed using homebrew: brew install rename.

  • This did not work on my machine (Arch Linux), but mik's answer did. – marcvangend Apr 21 '17 at 8:14
  • @marcvangend Which version of rename are you using? # sudo pacman -S perl-rename will install the perl version, which is more powerful and might be enough to make this answer work for you. – John Gowers May 20 '17 at 19:40
  • @JohnGowers Thanks! I didn't realize there are two versions. On my system, rename --version returns rename from util-linux 2.29.2 so that is indeed not the perl version. – marcvangend May 20 '17 at 21:53
  • 4
    There are two common rename utilities but neither of them are developed by GNU: Debian-based distributions include a rename utility with their Perl package while Red Hat-based distributions use the rename utility from the util-linux from the Linux Kernel Organization. Your link is to the rename C function from the GNU standard library. – Anthony Geoghegan Jul 7 '17 at 9:16
  • In this answer, why do we have to write /g in rename 's/#U00a9/safe/g' * – Nikhil Jul 9 '18 at 21:25
17

This is not hard, simply make sure to escape the octothorpe (#) in the name by prepending a reverse-slash (\).

find . -type f -name 'Lucky-*' | while read FILE ; do
    newfile="$(echo ${FILE} |sed -e 's/\\#U00a9/safe/')" ;
    mv "${FILE}" "${newfile}" ;
done 
  • Your explanation makes sense, escaping the # sounds like what I need. I do not see a backslash in your example. Should it look like this: s/\#U00a9/safe/ – Leon Francis Shelhamer Dec 19 '14 at 23:45
  • @LeonFrancisShelhamer good catch. It swallowed the backslash. I'll modify. – DTK Dec 20 '14 at 1:06
12

To escape # from the shell, just use single quotes ('#'), double quotes ("#"), or backslash (\#).

The simplest in your case would be to use the rename command (if it is available):

rename '#U00a9' safe *.jpg
  • 2
    Thanks. While the highest voted answer (rename 's/#/somethingelse/' *) didn't work on my machine (Arch Linux), this one did. – marcvangend Apr 21 '17 at 8:13
  • 1
    This works using the rename command from util-linux. – imclean May 17 at 4:14
11

find the list of files and then replace keyword. below is example

find . -name '*jpg' -exec bash -c ' mv $0 ${0/\#U00a9NBC/safeNBC}' {} \;

enter image description here

  • You need some double-quotes around your mv arguments, in case there are spaces in the name – OrangeDog Oct 3 '18 at 12:52
6

not sure how to in sed, but you can try this in a bash shell:

for f in Lucky-#U00a9NBC-*.jpg; do mv -v "$f" "${f/#U00a9/safe}"; done;

explanation:

  1. loops through all file names matching the glob (Lucky-#U00a9NBC-*.jpg)
  2. renames file using the move command(mv)
  3. uses native bash parameter substitution ${var/Pattern/Replacement} to craft the new name ("${f/#U00a9/safe}")

More on parameter substitution (which is highly underutilized IMO): http://www.tldp.org/LDP/abs/html/parameter-substitution.html

  • While this code may answer the question, it isn’t very useful by itself. Explaining how it solves the problem would improve the usefulness and long-term value of the answer. – Anthony Geoghegan Sep 2 '16 at 10:16
  • added walkthrough explanation and further reading as per Anthony's comment. – Gregory Patmore Oct 5 '16 at 16:11
1

The above examples were not working on my system (CentOS 5.6) so I found a (possibly more system-specific) command that works (note: need to escape '#' with \ on command line):

rename \#U00a9 safe *.jpg

[Also: I don't have enough reputation yet to comment, so in response to Nikhil's question regarding the use of /g in rename 's/old_string/new_string/g' (posed in the comments for another answer above):

Use the g modifier to perform a 'global' substitution (that is, to substitute new_string for old_string as many times as old_string occurs). This shouldn't be necessary in my answer because the rename will be applied to all files specified with *. See https://www.computerhope.com/unix/rename.htm for a concise explanation of this and other modifiers.]

  • Correct; Fedora-derived OSes like CentOS have a different version of rename than Debian-derived OSes. See unix.stackexchange.com/a/238862/135943. And by the way, CentOS 5.6 is quite old and I recommend you upgrade. – Wildcard Aug 15 '18 at 19:23
  • Ah, thanks for the explanation + link. The outdated OS is at work and so it isn't up to me to upgrade :) but a new cluster is being built out and presumably we'll upgrade when we move over... – Ezra Citron Aug 17 '18 at 17:02
0

Here's DTK's solution wrapped in reusable bash function:

function renameFilesRecursively () {

  SEARCH_PATH="$1"
  SEARCH="$2"
  REPLACE="$3"

  find ${SEARCH_PATH} -type f -name "*${SEARCH}*" | while read FILENAME ; do
      NEW_FILENAME="$(echo ${FILENAME} | sed -e "s/${SEARCH}/${REPLACE}/g")";
      mv "${FILENAME}" "${NEW_FILENAME}";
  done

}

Here's how you can use it:

renameFilesRecursively /home/user/my-files apple orange
-1

Another option is to use pyRenamer, an application made specifically for batch renaming.

It can be installed with sudo apt-get install pyrenamer

For usage details, refer to its README file on GitHub.

  • 1
    If you really think this could answer the question please add some explanation to your answer. Of itself, it only installs a package. You should explain what the command does and provide an example that handles the OP's specific requirement. – roaima Sep 2 '16 at 10:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy