using find with exec - bash

I want to copy files found by find (with exec cp option) but, i'd like to change name of those files - e.g find ... -exec cp '{}' test_path/"test_"'{}' , which to my test_path should copy all files found by find but with prefix 'test'. but it ain't work.
I'd be glad if anyone could give me some ideas how to do it.
best regards

for i in `find . -name "FILES.EXT"`; do cp $i test_path/test_`basename $i`; done
It is assumed that you are in the directory that has the files to be copied and test_path is a subdir of it.

if you have Bash 4.0 and assuming you are find txt files
cd /path
for file in ./**/*.txt
do
echo cp "$file" "/test_path/test${file}"
done
of with GNU find
find /path -type f -iname "*.txt" | while read -r -d"" FILE
do
cp "$FILE" "test_${FILE}"
done
OR another version of GNU find+bash
find /path -type f -name "*txt" -printf "cp '%p' '/tmp/test_%f'\n" | bash
OR this ugly one if you don't have GNU find
$ find /path -name '*.txt' -type f -exec basename {} \; | xargs -I file echo cp /path/file /destination/test_file

You should put the entire test_path/"test_"'{}' in ""
Like:
find ... -exec cp "{}" "test_path/test_{}" \;

I would break it up a bit, like this;
for line in `find /tmp -type f`; do FULL=$line; name=`echo $line|rev|cut -d / -f -1|rev` ; echo cp $FULL "new/location/test_$name" ;done
Here's the output;
cp /tmp/gcc.version new/location/test_gcc.version
cp /tmp/gcc.version2 new/location/test_gcc.version2
Naturally remove the echo from the last part, so it's not just echo'ng what it woudl of done and running cp

Related

Run a function on all filenames in a list

I use ag to select filenames and pipe them into fzy with the following script
set "$(ag -g "\.gz$" archives/ | fzy )"
echo "selected file: $1"
How can I run a function on all files in the folder archives , so only files in are selected, that are newer than already existing files with the same name the folder itp-files/? and pipe only those into fzy then?
I tried something like
for f in $(ag --nonumbers -g "\.gz$" archives/); do
echo do something with $f and only output if file is older than the same in itp-files/;
done | fzy
But I am not sure how to compare the filetimes ike this
I tried something like
for f in $(ag --nonumbers -g "\.gz$" archives/); do
echo do something with $f and only output if file is older than the same in tmp/;
done | fzy
But I am not sure how to compare the filetimes ike this
If you like your construction for ... in ... with ag, you may compare timestamps like this:
for f in $(ag --nonumbers -g "\.gz$" archives/); do
fn=$(basename $f)
if [ $f -ot tmp/$fn ]; then
fzy $f
fi
done
Ajust full path of tmp folder, if needed.
-ot means "older than".
Narrowed solution (to provide a list of newline-separated items for fzy):
find archives -iname "*.gz" -type f -printf "%f\n" | \
xargs -I '{}' find itp-files -name '{}' -type f -newer '{}' -printf "%f\n" | \
sort | \
fzy
You can use the xargs command to run a command on each line of output.
For example: find . -name '*.bak' -type f -print | xargs rm -r will remove all files that end in .bak
I believe you need the find -exec approach, something like:
find /directory -name "*.gz" -mtime +5 -exec ag -g {} \; | fzy
This means:
Search within the /directory
The name of the file needs to end with .gz (file extension)
The last modification date needs to be older than 5 days (can be altered according to your wishes)
-exec ag -g {} : executed the ag command, using the -g switch, on the find result ({}).
\; ends the -exec part.
You can launch the fzy command on the results.
Feel free to add comments in case you have doubts.

extract text informations from many subfolders

I'm looking to extract informations from subfolders.
I have a folder containing several folders containing several folders with text file information.
I've done something like this, but it works only when text files have different names (otherwise files with same names are erased by the most recent ones):
mkdir target_directory
pwd=`pwd`
find $pwd . -name \*.txt -exec cp {} target_directory \;
cd target_directory
cat *.txt > all-info
rm *.txt
I was thinking to had directory to the name of extracted files. How can I do that?
Maybe there is a smarter way?
Thank you!
If your goal is to concatenate all *.txt files in target_directory/all-info then just use cat {} in the exec action of your find command and redirect the output:
$ mkdir -p target_directory
$ find . -type f -name '*.txt' -exec cat {} \; > target_directory/all-info
This should do the trick:
mkdir -p target_directory
find . -name "*.txt" -exec cat {} >> target_directory/all-info \;
Man-pages of cp mention:
-n, --no-clobber
do not overwrite an existing file (overrides a previous -i option)
So I think your solution (only the find part) should be:
find $pwd . -name \*.txt -exec cp -n {} target_directory \;

Rename files in several subdirectories

I want to rename a file present in several subdirectories using bash script.
my files are in folders:
./FolderA/ABCD/ABCD_Something.ctl
./FolderA/EFGH/EFGH_Something.ctl
./FolderA/WXYZ/WXYZ_Something.ctl
I want to rename all of the .ctl file with the same name (name.ctl).
I tried several command using mv or rename but didnt work.
Working from FolderA:
find . -name '*.ctl' -exec rename *.ctl name.ctl '{}' \;
or
for f in ./*/*.ctl; do mv "$f" "${f/*.ctl/name .ctl}"; done
or
for f in $(find . -type f -name '*.ctl'); do mv $f $(echo "$f" | sed 's/*.ctl/name.ctl/'); done
Can you help me using bash?
thanks
You can do this with one line with:
find . -name *.ctl -exec sh -c 'mv "$1" `dirname "$1"`/name.ctl' x {} \;
The x just allows the filename to be positional character 1 rather than 0 which (in my opinion) wrong to use as a parameter.
Try this:
find . -name '*.ctl' | while read f; do
dn=$(dirname "${f}")
# remove the echo after you sanity check the output
echo mv "${f}" "${dn}/name.ctl"
done
find should get all the files you want, dirname will get just the directory name, and mv will perform the rename. You can remove the quotes if you're sure that you'll never have spaces in the names.

"find" command with a variable directory

I'm trying to list the files in a directory that is given by the variable DIR. My code looks like this so far:
for i in `find $DIR -name "*.txt"
The variable DIR is already defined. I'm not sure what the syntax is here.
ls "${DIR}/*.txt"
or
find "${DIR}" -name "*.txt"
should do the trick. The first one only lists *.txt files in the directory itself, the second one also *.txt files in subdirectories.
I guess you want to execute a given action on all files with extension "txt" under $DIR and/or its subdirs. As usual there are different solutions.
This one:
$ for i in $(find "$DIR" -name \*.txt) ; do echo "Do something with ${i}" ; done
won't work if file path (either the file itself or one subdirectory) contains spaces.
But you can use this:
$ find "$DIR" -type f -name \*.txt | while read i ; do echo "Do something with ${i}" ; done
or this:
$ find "$DIR" -type f -name \*.txt -print0 | xargs -0 -I {} echo "Do something with {}"
or this:
$ find "$DIR" -type f -name \*.txt -exec echo "Do something with {}" \;
or... 100 additional solutions.
Not sure what you want.
find $DIR -name "*.txt" -print
will list all the files that end with .txt and are located in $DIR or its subdirectories. You can omit the -print as that is the default behaviour anyway.
If you have a simple thing you want to do with this file, you can use find's -exec function:
find $DIR -name "*.txt" -exec wc -l {} \;
Or you can use a loop:
for f in `find $DIR -name "*.txt"`; do
wc -l $f
mv $f /some/other/dir/
fi
note: as #mauro helpfully pointed out, this will not work if the DIR or the file names contain spaces.
Cheers

removing files that have extension .bin then printing bye

filename=file.bin
extension=$(echo ${filename}|awk -F\. '{print $2}')
if [ ${extension} == "bin" ]; then
rm *.extenstion
fi
would something like this work how do I delete all files that have the same extention in a folder
You don't need to extract the extension yourself, this is what globbing is for. Simply do:
rm *.bin
Or recursively find ./ -name "*.bin" -exec rm -f {} \;
Aside from globbing, this is also doable with find.
find -type f -name "*.bin" -exec rm {} \;
Or more efficiently, with newer version of find:
find -type f -name "*.bin" -exec rm {} +
which is equivalent to
find -type f -name "*.bin" | xargs rm
Note: by default, find will do it recursively.

Resources