This is what I tried:
find . -name *.sv | xargs sed -i -e '<command>' -e '<command>'
It does not work. Using the exact same command on each file still works.
Thanks for the help.
This is what I tried:
find . -name *.sv | xargs sed -i -e '<command>' -e '<command>'
It does not work. Using the exact same command on each file still works.
Thanks for the help.
To force xargs
to only execute sed
with a single file at a time, use -n 1
with xargs
. You should also pass the pathnames from find
using -print0
and get xargs
to receive them with -0
(if your find
and xargs
supports these nonstandard options), so that pathnames containing spaces etc. are handled correctly. You probably also need to specify that you are looking for regular files (and not directories etc.) and you definitely need to quote that shell glob (or it may expand to any matching filename in the current directory):
find . -type f -name '*.sv' -print0 | xargs -0 -n 1 sed -i -e '<command>' -e '<command>'
Or, just use find
:
find . -type f -name '*.sv' -exec sed -i -e '<command>' -e '<command>' {} ';'
Related:
A solution that is not using find
, but instead uses the **
globbing pattern (matches "recursively" down into subdirectories) available in bash
after doing shopt -s globstar
:
shopt -s globstar dotglob nullglob
for pathname in ./**/*.sv; do
if [[ -f "$pathname" ]] && [[ ! -h "$pathname" ]]; then
sed -i -e '<command> -e '<command>' "$pathname"
fi
done
This loop loops over all files that have a filename suffix .sv
and tests whether each matched name is a regular file (we have to test separately with ! -h
to make sure its not a symbolic link to a regular file) before applying the sed
command. The shell options enable the use of **
(globstar
), matching of hidden names (dotglob
), and removes the patterns completely if it does not match (nullglob
).
Or, with the zsh
shell, which has **
enabled by default, and can use a "glob qualifier" to do most of the "extra" work that bash
has to do explicitly:
for pathname in ./**/.sv(.DN); do
sed -i -e '<command> -e '<command>' "$pathname"
done
The glob qualifier (.DN)
modifies the preceding globbing pattern so that it matches only regular files, matches hidden names, and expands to nothing if there is no match at all.
-i
imply -s
(i.e. that sed will treat the files as separate, even if xargs doesn't)?
– steeldriver
Jun 05 '18 at 19:15
sed
very often (and never with -i
). The original command may still have issues with whitespace in file names though (and the other issues).
– Kusalananda
Jun 05 '18 at 19:31
-e
options on the sed
. -e
denotes a sed
script will follow, not a sed
command. sed -e '<command1> ; <command2>' FILE
works just fine.
– Centimane
Jun 06 '18 at 10:25
-e
denotes that the following argument is a sed
expression or command. -f
is used to read a script from a file. There is no benefit to combining the arguments of several -e
into a single string, and in some cases, it's even impossible to do so.
– Kusalananda
Jun 06 '18 at 11:12
-e
denotes a script as per the man page: "add the script to the commands to be executed". I don't think there are any cases where it's impossible, you just might have to escape some characters if using double-quotes instead of single. It is true though that the result is the same, but it's good to recognize that -e
is for passing a script rather than a single command.
– Centimane
Jun 06 '18 at 11:48
script
but calls it "the editing commands", so I think we may both call ourselves correct on that point. If you want to use the sed
command a
or i
, it's nice looking to use -e 'i\' -e 'text'
than to embed a newline in the single quoted string. Regardless of all of this, whether one or several -e
is used (or none) is totally unimportant to this question.
– Kusalananda
Jun 06 '18 at 12:03
Here is another method that worked for me:
find -name "*.fail" | xargs -L 1 sed -i -e 's/cse/ecs/g' -e 's/trex/dino/g'