Find and exec command in linux. Is it possible to pipe 2 find and exec commands - linux

I'm trying to accomplish this task
1) Find directory A (DIR_A) and copy all files in the directory(including its sub-directory, if any) into a new directory called DIR_B
2) In directory (DIR_B),replace the word apple with orange
I executed the following code and for some reason, it copies all the files but it fails on the second task (replace apple with orange). I would appreciate help on this. Below is my code
find DIR_A -iname FILEA -type f -exec cp {} DIR_B \;|find DIR_B/ -iname \*.* -type f -exec sed -i "s|apple|orange|g" {} \;

Rather than trying to piping the output from one find into the other, why not just run them sequentially? I'm not sure that find reads from its stdin.
find DIR_A -iname FILEA -type f -exec cp {} DIR_B \; ; find DIR_B/ -iname \*.* -type f -exec sed -i "s|apple|orange|g" {} \;
I've replaced your pipe with a semi-colon.

Try this :
Sed Syntax :
sed 's/old/new/g'
find DIR_A -iname FILEA -type f -exec cp {} DIR_B \;|find DIR_B/ -iname \*.* -type f -exec sed -i "s/apple/orange/g" {} \;

Related

I want to get an output of the find command in shell script

Am trying to write a script that finds the files that are older than 10 hours from the sub-directories that are in the "HS_client_list". And send the Output to a file "find.log".
#!/bin/bash
while IFS= read -r line; do
echo Executing cd /moveit/$line
cd /moveit/$line
#Find files less than 600 minutes old.
find $PWD -type f -iname "*.enc" -mmin +600 -execdir basename '{}' ';' | xargs ls > /home/infa91punv/find.log
done < HS_client_list
However, the script is able to cd to the folders from HS_client_list(this file contents the name of the subdirectories) but, the find command (find $PWD -type f -iname "*.enc" -mmin +600 -execdir basename '{}' ';' | xargs ls > /home/infa91punv/find.log) is not working. The Output file is empty. But when I run find $PWD -type f -iname "*.enc" -mmin +600 -execdir basename '{}' ';' | xargs ls > /home/infa91punv/find.log as a command it works and from the script it doesn't.
You are overwriting the file in each iteration.
You can use xargs to perform find on multiple directories; but you have to use an alternate delimiter to avoid having xargs populate the {} in the -execdir command.
sed 's%^%/moveit/%' HS_client_list |
xargs -I '<>' find '<>' -type f -iname "*.enc" -mmin +600 -execdir basename {} \; > /home/infa91punv/find.log
The xargs ls did not seem to perform any useful functionality, so I took it out. Generally, don't use ls in scripts.
With GNU find, you could avoid the call to an external utility, and use the -printf predicate to print just the part of the path name that you care about.
For added efficiency, you could invoke a shell to collect the arguments:
sed 's%^%/moveit/%' HS_client_list |
xargs sh -c 'find "$#" -type f -iname "*.enc" -mmin +600 -execdir basename {} \;' _ >/home/infa91punv/find.log
This will run as many directories as possible in a single find invocation.
If you want to keep your loop, the solution is to put the redirection after done. I would still factor out the cd, and take care to quote the variable interpolation.
while IFS= read -r line; do
find /moveit/"$line" -type f -iname "*.enc" -mmin +600 -execdir basename '{}' ';'
done < HS_client_list >/home/infa91punv/find.log

sed ack search / replace line break with string

I have looked into a few SO threads, non of which have helped my specific situation.
I am trying to update a PHP app that I took over from php 5.6 to php 8.0
With that said there are MANY instances that look like:
<?
echo ...
function
I need to find all cases where <? is followed directly by a newline and replace it with <?php(newline)
Per the SO posts I've read .. I think I am coming close with the following:
find ./ -type f -readable -writable -exec sed -i ":a;N;$!ba;s/\<\?\n/\<\?php\n/g" {} \;
I think I am close .. But I can't figure out why it won't replace <?\n with <?php\n as the sed statement works without the newline. But per THIS POST it looks like I am doing it correctly.
What am I doing wrong?
Iterations I've tried:
$ find ./ -type f -readable -writable -exec sed -i ":a;N;$!ba;s/\<\?\n/\<\?php\n/g" {} \;
$ find ./ -type f -readable -writable -exec sed -i ":a;N;$!ba;s/<\?\n/<\?php\n/g" {} \;
$ find ./ -type f -readable -writable -exec sed -i ":a;N;$!ba;s/<?\n/<?php\n/g" {} \;
$ find ./ -type f -readable -writable -exec sed -i ":a;N;$!ba;s/<?\n\r/<?php\n/g" {} \;
$ find ./ -type f -readable -writable -exec sed -i ":a;N;$!ba;s/<?\r\n/<?php\n/g" {} \;
The sed command itself could be something as simple as:
sed -i 's/<?$/<?php/'
Glue that together with find and it might work for you.
$ is an anchor matching the end of a line, you might consider using ^ to anchor the match to the beginning as well:
s/^<?$/<?php/

Formatting md5sum differently?

I need to find the md5sum of files recursively and list these files alphabetically. However, in my final output I don't want the sum to actually show up. For example if I issue:
find -not -empty -type f -exec md5sum "{}" \;
I get this:
0df8724ef24b15e54cc9a26e7679bb90 ./doc1.txt
d453430ce039863e242365eecaad7888 ./doc2.txt
53b2e8ae1dfaeb64ce894f75dd6b957c ./test.sh~
1ba03849883277c3c315d5132d10d6f0 ./md5file.txt
6971b4dbbd6b5b8d1eefbadc0ecd1382 ./test.sh
is there a simple way make this command to show only the files like:
./doc1.txt
./doc2.txt
./test.sh~
./md5file.txt
./test.sh
thx!
As Cyrus and Sriharsha say, simply using:
find -not -empty -type f
will give you the result you need.
Pass the output of find command to awk or cut.
find -not -empty -type f -exec md5sum "{}" \; | awk '{print $2}'
OR
Use sed if the filename contains spaces.
find -not -empty -type f -exec md5sum "{}" \; | sed 's/^[^ ]\+ \+//'

find command to find files and concatenate them

I am trying to find all the files of type *.gz and cat them to total.gz and I think I am quite close on this.
This is the command I am using to list all *.gzfiles:
find /home/downloaded/. -maxdepth 3 -type d \( ! -name . \) \
-exec bash -c "ls -ltr '{}' " \
How to modify it so that it will concatenate all of them and write to ~/total.gz
Directory structure under downloaded is as follows
/downloaded/wllogs/303/07252014/SysteOut.gz
/downloaded/wllogs/301/07252014/SystemOut_13.gz
/downloaded/wllogs/302/07252014/SystemOut_14.gz
Use cat in -exec and redirect output of find:
find /home/downloaded/ -type f -name '*.gz' -exec cat {} \; > output
Use echo in -exec and redirect the output:
find /home/downloaded/ -name "*.gz" -exec echo {} \; > output

Using find command on in a Bash Script to find integers

I need to find and archive files with a certain file name e.g. ABC_000.jpg
find ~/my-documents/ -iname "ABC_***.JPG" -type f -exec cp {} ~/my-documents/archive/ \;
however I can not seem to find a way to limit the find function to find only 3 integers as there are files that are named ABC_CBA.jpg that I do not want included
Try this find:
find ~/my-documents/ -iname "ABC_[0-9][0-9][0-9].JPG" -type f -exec cp '{}' ~/my-documents/archive/ \;
EDIT: Or using regex:
find -E ~/my-documents/ -iregex ".*ABC_[0-9]{3}\.JPG" -type f -exec cp '{}' ~/my-documents/archive/ \;

Resources