Search code examples
gitbashreplacesedxargs

Confusing error from | xargs sed


I have a little find-replace utility around git. Let's ignore suggestions for a different approach ATM. I'm really trying to understand this error from sed. Take a look at the command

function git_find_replace
{
    local grepexp="$1"
    local replace="$2"

    # build sed command
    local sedcmd="s/$grepexp/$replace/g"

    # First find the files; then pipe through xargs sed for replacement
    git grep --name-only "$grepexp" | xargs sed -r "$sedcmd" -i ''
}

The command works, and I get the expected results, however, when I run this on one of my repositories, I get an error from sed

sed: can't read : No such file or directory

But the git component returns a set of files that all exist (slightly mangled for sake of post)

git grep --name-only 0.46.1
release/a.html
release/resources/javascript/a.js
release/resources/version
release/index.html
release/installer.html

I've verified the existence of these files manually with ls. For example, if I change the xargs component to this

git grep --name-only 0.46.1 | xargs ls -l

There are no complaints from ls about missing files or directories. So why do I get an error from sed?

Update

To save you some digging through the answers and comments, this turned out to be a difference between BSD and GNU versions of sed. See this thread for more.


Solution

  • If you pass an extension to sed -i, it needs to be adjoined to the -i, as in sed -i.bak myfile. It can't be a separate argument. sed -i .bak myfile would cause sed to do in place editing of files named .bak and myfile.

    When you write sed -i '' sed tries to do in place editing on a file whose name is the empty string.

    If you don't want backup files made, just leave off the argument entirely. No ''.

    git grep --name-only "$grepexp" | xargs sed -r "$sedcmd" -i