Command-line tip: replace a word in all files in a directory

Thu, Jun 27, 2013 - 2:37am -- Isaac Sukin

I need to use this command every once in awhile and I always forget how to do it off the top of my head.

grep -lr --exclude-dir=".git" -e "oldword" . | xargs sed -i "s/oldword/newword/g"

If you're on Windows you'll need unix command-line tools installed. The easiest way to do that is with Gow.

Here's what each piece does:

  • grep searches for text in files recursively in a directory.
  • The -l flag for grep tells it to only output file names when it finds a word match.
  • The -r flag tells grep to search recursively in the directory, i.e. it will also look in subfolders if applicable.
  • --exclude-dir=".git" is optional; it tells grep to ignore files in the .git directory. You can have more than one --exclude-dir flag if you want to exclude multiple folders. Usually you won't want to look in the git folder though, if your folder is being tracked by git. Similarly, you can use the --exclude flag to exclude files with certain patterns in their names, for example --exclude="*\.min\.*" will exclude files with .min. in their names.
  • -e "oldword" The -e flag says that the following argument is a regular expression and can be omitted if you just want to type in a normal word or phrase. "oldword" is the old word/expression you want to replace.
  • The dot (.) tells grep to look in the current directory. You can change that to a directory path, a specific file, or an asterisk (*) if you want to search files in the current directory non-recursively.
  • The pipe (|) tells xargs to operate on the output of the grep command.
  • xargs tells sed to use the output of grep.
  • sed -i modifies text files.
  • "s/oldword/newword/g" tells sed to replace every instance of oldword with newword. "s" means replace and "g" means every instance (as opposed to just the first one). oldword and newword are regular expressions. You can omit newword if you just want to delete a word.

If you only want to operate on a single file and you already know which one it is, you can skip the grepping and just use sed. Wikipedia has a bunch of examples.

Update: @collinalexbell points out that you can append -D skip to the grep command to prevent it from processing mounted devices and sockets in the top level of the directory you're searching.