Skip to content

Instantly share code, notes, and snippets.

@azimidev
Last active June 2, 2021 21:16
Show Gist options
  • Save azimidev/d47bfbce9ee101890a6ad175693f76fb to your computer and use it in GitHub Desktop.
Save azimidev/d47bfbce9ee101890a6ad175693f76fb to your computer and use it in GitHub Desktop.
FInd and replace Unix
  1. Replacing all occurrences of one string with another in all files in the current directory: These are for cases where you know that the directory contains only regular files and that you want to process all non-hidden files. If that is not the case, use the approaches in 2.

All sed solutions in this answer assume GNU sed. If using FreeBSD or OS/X, replace -i with -i ''. Also note that the use of the -i switch with any version of sed has certain filesystem security implications and is inadvisable in any script which you plan to distribute in any way.

Non recursive, files in this directory only:

sed -i -- 's/old/new/g' *
perl -i -pe 's/old/new/g' ./* 

(the perl one will fail for file names ending in | or space)).

Recursive, regular files (including hidden ones) in this and all subdirectories

find . -type f -exec sed -i 's/old/new/g' {} +

If you are using zsh:

sed -i -- 's/old/new/g' **/*(D.)

(may fail if the list is too big, see zargs to work around).

Bash can't check directly for regular files, a loop is needed (braces avoid setting the options globally):

( shopt -s globstar dotglob;
    for file in **; do
        if [[ -f $file ]] && [[ -w $file ]]; then
            sed -i -- 's/old/new/g' "$file"
        fi
    done
)

The files are selected when they are actual files (-f) and they are writable (-w).

  1. Replace only if the file name matches another string / has a specific extension / is of a certain type etc: Non-recursive, files in this directory only:
sed -i -- 's/old/new/g' *baz*    ## all files whose name contains baz
sed -i -- 's/old/new/g' *.baz    ## files ending in .baz

Recursive, regular files in this and all subdirectories

find . -type f -name "*baz*" -exec sed -i 's/old/new/g' {} +

If you are using bash (braces avoid setting the options globally):

( shopt -s globstar dotglob
    sed -i -- 's/old/new/g' **baz*
    sed -i -- 's/old/new/g' **.baz
)

If you are using zsh:

sed -i -- 's/old/new/g' **/*baz*(D.)
sed -i -- 's/old/new/g' **/*.baz(D.)

The -- serves to tell sed that no more flags will be given in the command line. This is useful to protect against file names starting with -.

If a file is of a certain type, for example, executable (see man find for more options):

find . -type f -executable -exec sed -i 's/old/new/g' {} +

zsh:

sed -i -- 's/old/new/g' **/*(D*)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment