I'm getting an error with the following
find . -name "*" -type f | xargs grep -l "xyz" | sed -i '' 's/'${line}'/'${rep}'/g'
sed: -i may not be used with stdin
what's gone wrong?
Asuming that you're trying to sed something only in the files that contain xyz, you will have to xargs again
find . -name "*" -type f | xargs grep -l "xyz" |xargs sed -i "s/'${line}'/'${rep}'/g"
-i is for inline file editing and you are just piping find command's output to sed in stdin hence that error shows up.
Try this find command instead:
find . -name "*" -type f -exec sed -i '' "s/${line}/${rep}/g" '{}' \;
PS: -name "*" can also be skipped here.
When we are using the find command we can't connect the output with the pipe( | ). So you can use the -exec with find command to execute more commands.
Related
I have crafted this sed command which looks to be working fine, only it's being applied to all the files in my directory :
find . -type f -name '*.js' -not -path './node_modules/*' -exec sed -i .bak -E '
1i\
const env = require('\''env-var'\'');
s/(^|[^[:alnum:]_])process\.env\.([[:alnum:]_]+) \|\| ([[:alnum:]_]+)($|[^[:alnum:]_])/\1env.get('\''\2'\'').default('\''\3'\'')\4/g
s/(^|[^[:alnum:]_])process\.env\.([[:alnum:]_]+)($|[^[:alnum:]_])/\1env.get('\''\2'\'')\3/g
' {} \;
I wish to apply those transformations only to the files which match this grep command :
grep -r "process\.env\." --exclude-dir=node_modules
I tried using the pipe but I can't make the two working together. What's the right way to handle it?
EDIT: I tried this
➜ app-service git:(chore/adding-env-example) ✗ grep -r "process\.env\." --exclude-dir=node_modules | sed -i .bak -E '
1i\
const env = require('\''env-var'\'');
s/(^|[^[:alnum:]_])process\.env\.([[:alnum:]_]+) \|\| ([[:alnum:]_]+)($|[^[:alnum:]_])/\1env.get('\''\2'\'').default('\''\3'\'')\4/g
s/(^|[^[:alnum:]_])process\.env\.([[:alnum:]_]+)($|[^[:alnum:]_])/\1env.get('\''\2'\'')\3/g
' {} \;
sed: {}: No such file or directory
I want only the files containing process.env.SOMETHING to be edited.
Work with pipes. xargs comes handy:
find ... -print |
xargs -d '\n' grep -l 'regex' |
xargs -d '\n' sed 'stuff'
xargs: illegal option -- d
You can:
install GNU xargs
install GNU parallel
write a bash loop to read the files line by line, see https://mywiki.wooledge.org/BashFAQ/001
make sure your files do not have spaces or tabs or newlines in filnames and just remove -d '\n' option.
Suggesting to reverse order of commands. sed on filtered list of files.
Files filter is combination of grep filter on find filter: grep -l "process\.env\." $(find . -type f -name '*.js' -not -path './node_modules/*').
sed -i .bak -E '
1i\
const env = require('\''env-var'\'');
s/(^|[^[:alnum:]_])process\.env\.([[:alnum:]_]+) \|\| ([[:alnum:]_]+)($|[^[:alnum:]_])/\1env.get('\''\2'\'').default('\''\3'\'')\4/g
s/(^|[^[:alnum:]_])process\.env\.([[:alnum:]_]+)($|[^[:alnum:]_])/\1env.get('\''\2'\'')\3/g
' $(grep -l "process\.env\." $(find . -type f -name '*.js' -not -path './node_modules/*'))
I am writing a command using find, grep and sort to display a sorted list of all files that contain 'some-text'.
I was unable to figure out the command.
Here is my attempt:
$find . -type f |grep -l "some-text" | sort
but it didn't work.
You need to use something like XARGS so that the content of each file passed through the pipe | is made available for grep.
XARGS: converts input from standard input into arguments to a command
In my case, I have files1,2,3 and they contain the word test. This will do it.
za:tmp za$ find . -type f | xargs grep -l "test" | sort
./file1.txt
./file2.txt
./file3.txt
or
za:tmp za$ find . -type f | xargs grep -i "test" | sort
./file1.txt:some test string
./file2.txt:some test string
./file3.txt:some test string
You can use it in any unix:
find . -type f -exec sh -c 'grep "some text" {} /dev/null > /dev/null 2>&1' \; -a -print 2> /dev/null|sort
A more optimized solution that works only with GNU-grep:
find . -type f -exec grep -Hq "some-text" {} \; -a -print 2> /dev/null|sort
I try this command to find and replace string in my android project.
find . -name '*.java' -print0 | xargs -0 sed -i "" "s;//\#Logger\.;Logger\.;g"
//#Logger. => Logger.
It's work but in some files i have unexpected changes. With git diff i get:
-}
\ No newline at end of file
+}
How to fix it?
Well, just figured out the problem.
Your code should work as following (remove redundand "" after -i in sed):
find . -name '*.java' -print0|xargs -0 sed -i "s;//\#Logger\.;Logger\.;g"
Alternatively you can use parallel instead xargs and run this even faster:
find . -name '*.java' -print0|parallel -0 sed -i "s;//\#Logger\.;Logger\.;g" {}
And suggested below find .. -exec variant:
find . -name '*.java' -exec sed -i "s;//\#Logger\.;Logger\.;g" {} +;
I'm trying to run the command
find . -name "*.csv" | xargs -I{} cat '{}' > Everything2.csv
and I get back:
cat: ./Everything2.csv: input file is output file
What does this mean?
As shown in that answer, you should run:
$ find . -name '*.csv' -exec cat {} + | tee Everything2.csv
since redirection operator (> or >>) has a higher precedence, therefore it creating/truncating the file, before the find command is invoked. So to avoid that you need to generate the list first, then pipe it into the file, but without using redirection operator, so tee in this cause works fine.
Alternatively use sponge instead of cat which soaks up standard input and write to a file:
find . -name "*.csv" | xargs -I{} sponge '{}' > Everything2.csv
Tell find to exclude the output file from its results to prevent this loop:
find . -name Everything2.csv -prune -o \
-name '*.csv' -exec cat {} + \
>Everything2.csv
I would like to replace the part of each file path, which will be find by find linux command.
My approach is attached below:
find . -type f -name "*.txt" -exec echo {} | sed "s/f/u/g" {} \;
I expect the replacement of each letter "f" with "u" in file path. Unfortunately I got this error:
find: missing argument to `-exec'
sed: can't read {}: No such file or directory
sed: can't read ;: No such file or directory
What I did wrong? Thank you for your help.
I would like to replace the part of each file path
If you want to change just the file names/paths then use:
find . -type f -name "*.txt" -exec bash -c 'echo "$1" | sed "s/f/u/g"' - {} \;
or a bit more efficient with xargs (since it avoids spawning subshell for each found file):
find . -type f -name "*.txt" -print0 |
xargs -0 bash -c 'for f; do sed "s/f/u/g" <<< "$f"; done'
find . -type f -name "*.txt" | while read files
do
newname=$(echo "${files}" | sed s"#f#u#"g)
mv -v "${files}" "${newname}"
done
I don't completely understand what you meant by file path. If you weren't talking about the file name, please clarify further.