intechops6
intechops6

Reputation: 1097

sed variable substitution using string

How to pass argument to sed without input files. The sed is in single quote and has pipe in it already.

git filter-branch -f --index-filter \
      'git ls-files -s | sed -i "s-\t\"*-&dirname/-" |
                GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
                git update-index --index-info &&
       mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD

The above code works fine if dirname is hard-coded. But i need to pass the dirname from command line arguments to script. I am trying like below but no luck.

 'set subdir=$folder;git ls-files -s | sed -i "s-\t\"*-&$subdir/-" |

The sed says input file is missing. I can not directly pass the input file to sed. I am seeing error like below.

Rewrite 9c86de42b7f3228e3d45a278c8caf7e24c8e55cf (1/2) (0 seconds passed, remaining 0 predicted)
sed: no input files

Upvotes: 0

Views: 371

Answers (2)

torek
torek

Reputation: 488233

You have two choices here. You can either evaluate $subdir to build up a fixed sed command that you then set as your filter; or you can evaluate a variable in the shell fragment that git filter-branch will invoke.

To understand the latter, realize that your --index-filter string becomes an ordinary shell variable:

--index-filter)
    filter_index="$OPTARG"
;;

which is then passed to eval:

eval "$filter_index" < /dev/null ||
    die "index filter failed: $filter_index"

The eval means that the expression in $filter_index, set from your --index-filter argument, has access to all the shell variables and functions in the filter-branch script. Unfortunately, none of its private variables holds the expression you'd like—but you can access its environment variables, which means you can put the value into an environment variable. In other words, you could supply subdir=<whatever> as an environment to your original expression.

In any case, as bk2204 answered, you need to remove the -i option. Besides that, some versions of sed don't accept \t as a tab character (presumably yours does, just be aware of this).

To expand the variable earlier, just do that. For instance:

... --index-filter \
    'git ls-files -s | sed "s-\t\"*-&'$folder'/-" | ...

(I've removed the -i here myself). Note how this exits single quotes, expands $folder, then re-enters single quotes. If $folder might contain whitespace, be sure to use double quotes while expanding it here:

... --index-filter \
    'git ls-files -s | sed "s-\t\"*-&'"$folder"'/-" | ...

The nesting of quotes here is pretty tricky: the stuff inside the single quotes is all one big string, provided as the argument that sets the variable $filter_index inside the filter-branch script. The eval runs it through a second pass of evaluation, breaking up into the pipeline (git ls-files, piped to sed, piped to git update-index) and running the various multiple commands, all of which have their stdin redirected to /dev/null.

Upvotes: 2

bk2204
bk2204

Reputation: 76519

You're using sed -i, which edits its command-line arguments (which are names of files) in place. However, you're reading from standard input and haven't provided any command-line arguments. If you want to just filter the standard input like this, omit the -i from your sed command.

Upvotes: 2

Related Questions