Use xargs.
... | xargs sed ...
Janis
> appreciate your help,
> miloody
Hi:
I write a shell script which first save the result of 'grep -lr 'cat'
*', and then use for loop feeding sed.
But why pipe command cannot work?
is there any rule about pipe, '|', command?
appreciate your help,
miloody
A pipe sends its output to the input of the next command; sed
expects filenames on the command line, not in its standard input.
--
Chris F.A. Johnson, author <http://shell.cfajohnson,com/>
===================================================================
Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
Pro Bash Programming: Scripting the GNU/Linux Shell (2009, Apress)
===== My code in this post, if any, assumes the POSIX locale =====
===== and is released under the GNU General Public Licence =====
> suppose i want to replace cat with dog in all the files within a
> folder, how could I reach that with grep and sed?
You'll need to get the file names to ‘sed’ on its own command line.
> i try to use "grep -lr 'cat' * |sed -ei 's/cat/deg/' ", but sed seems
> cannot eat the file names piped by grep.
Right, because you're piping the output of a process ‘grep …’ to the
input of another process ‘sed …’. But the ‘sed’ process is not looking
for file names on its standard input; it's expecting the file names on
its command line, and there are none there.
> How could I pass the file names to sed?
You can use ‘xargs(1)’ to read *its* standard input, and construct
command lines from the arguments that it reads.
Compare the output of this::
$ echo sed -ei 's/cat/dog/' foo bar baz
against the output of this::
$ grep -lr 'cat' * | xargs echo sed -ei 's/cat/dog/'
to understand what the role of ‘xargs’ is.
--
\ “The cost of education is trivial compared to the cost of |
`\ ignorance.” —Thomas Jefferson |
_o__) |
Ben Finney
take grep for example:
grep -rw 'cat' * -----> grep get its input from cmd line
find ./ -name '*.c' --> find get its input from cmd line
are these surmises correct?
thanks for your reply,
miloody
> Can I get the conclusion that pipe is the command that always send the
> result to the standard input of the next command?
Pipe is an operation within a command; but otherwise, yes, that's right.
Read the Bash man page (if you're using Bash) for more; piping is one of
the “redirection” operators.
> if so, how could I tell which command gets its input from standard
> input or command line?
By reading the documentation for each command that you want to use.
(Notice that standard input and command line are often *both* used, for
different purposes, among other sources of input.)
--
\ “Perhaps our role on this planet is not to worship God — but to |
`\ create Him.” —Arthur C. Clarke, 1972 |
_o__) |
Ben Finney
A pipe connects the standard output of one command to the standard
input of another command.
> if so, how could I tell which command gets its input from standard
> input or command line?
A command gets its parameters from the command line; its input
usually comes from standard input or files specified as paramteres
on the command line.
> take grep for example:
> grep -rw 'cat' * -----> grep get its input from cmd line
It gets its input from the files specified by, in this case, *. If
no file is specified, it uses stdin as input.
> find ./ -name '*.c' --> find get its input from cmd line
Its input doesn't come from the command line; the command line
tells it where to get its input.
> are these surmises correct?
No.
Try to run the part you have before the pipe first and see what output you get.
Then you can figure out if sed will find any cats in that list.
When I do things like that I use a perl oneliner like
perl -pi -e 's,cat,dog,g' *
but since you will do it recursive you can take your file list you created with
your grep.
perl -pi -e 's,cat,dog,g' $(grep -lr 'cat' *) unless it's to long list, or
includes file names with spaces.
/bb
You could do this many ways:
find . \
\! -name . -prune
-type f \
-exec \
grep -li 'cat' {} \;
-exec \
sed -ie 's/cat/dog/g' {} \;
for _f in ./* ./.[!.]* ./..?*; do
if [ -f "$_f" ] && [ ! -L "$_f" ]; then
if grep -li 'cat' < $_f > /dev/null; then
sed -ie 's/cat/dog/g' "$_f"
fi
fi
done
perl -e '
for (<./* ./.[!.]* ./..?*>) {
system("perl -i.BAK -0777e '/cat/ && s//dog/g' \"$_\"") if ! -l
&& -f _;
}
'
--Rakesh
You don't need both a match operator and a substitution operator.
> && -f _;
> }
> '
And you don't have to start a separate process to run the substitution:
perl -e'
$^I = ".BAK";
local $/;
for ( grep !-l && -f _, <./* ./.[!.]* ./..?*> ) {
@ARGV = $_;
s/cat/dog/g while <>;
}
'
Or also as:
perl -i.BAK -0777pe's/cat/dog/g' ./* ./.[!.]* ./..?*
John
--
The programmer is fighting against the two most
destructive forces in the universe: entropy and
human stupidity. -- Damian Conway
Thanks John for your masterly explanations.!
Has it ever crossed your mind (or O'Reilly's) to gather your perl-
one-
liner solutions from all over comp.unix.shell, comp.perl, etc.
& put them in a book form?
--Rakesh