Вопрос

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.

Это было полезно?

Решение

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

Другие советы

This isn't really an answer, it's a debugging step, but it's too long to put in a comment. Try creating a script called print_args:

#!/bin/bash
i=1
for arg
do
    printf "Arg %d = '%s'\n" $i "$arg"
    ((i++))
done

Then try:

git grep --name-only "$grepexp" | xargs ./print_args sed -r "$sedcmd" -i ''

This should show all the arguments being passed to sed, you may see something that explains why sed is parsing it incorrectly.

sed may be complaining because you are using the s/foo/bar/ command on values of $foo and/or $bar that may contain the delimiter -- /. Try s%foo%bar/ or s@foo@bar or some other delimiter you're confident will not appear.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top