add check file existences function while search and copy file - linux

I have use sudo find all files which match the file type and copy it to a file directory then tee the report.
I would like to include function to check file existence so that file from different folder will not overwrite the wrong file.
Please suggest an idea to fix my function also. Thank you.
sudo find / -iname "*.#fileType" -cp -v {} $directory \; | tee report.txt
function checkFile(){
if [ -f #filename];
then
# add number
fi
}

You can do this using the -exec option of find:
find / -type f -iname "*.#filetype" -exec cp --backup=numbered {} $directory \; -exec echo {} >> report.txt \;
With:
-exec cp --backup=numbered Will execute cp for each found file, with option --backup=numbered, which will prevent overwritting
-exec {} >> report.txt Which will add the copied file name to the report file.

Related

Shell cp: cannot stat no such file or directory

I was trying to use cp to copy files from one directory to another by globing
for files in index/*
do
file=$(echo $files|cut -d'/' -f2)
cp -r "$files" ".target/file"
done
However, cp will give this warning if the directory is empty. I tried 2>/dev/null to mute this message but it did not work. I wonder how I could fix it.
What about this: (not tested)
find /index -maxdepth 1 -type f -exec cp {} .target/ \;
-maxdepth 1 : only look in this directory
-type f : only take the files
-exec cp {} .target/ \; : execute a "file copy" action

How to copy list of folders keeping the partial folder structure that of parent directory

Say I want to copy some folders from find /40/AD/GWAS_data/Source_Plink/2021_ADGC_EOAD -name "plink_data*" which has these folders:
/40/AD/GWAS_data/Source_Plink/2021_ADGC_EOAD/ADGC_NHW/ADNI/TOPMEDr2/vcffile/plink_data
/40/AD/GWAS_data/Source_Plink/2021_ADGC_EOAD/ADGC_ASIAN/BIOCARD/TOPMEDr2/vcffile/plink_data
into /40/AD/GWAS_data/Source_Plink/2021_ADGC_EOAD/NEW_DIR/, but I want the new directory to have :
/40/AD/GWAS_data/Source_Plink/2021_ADGC_EOAD/NEW_DIR/ADGC_NHW/ADNI/TOPMEDr2/vcffile/plink_data
/40/AD/GWAS_data/Source_Plink/2021_ADGC_EOAD/NEW_DIR/ADGC_ASIAN/BIOCARD/TOPMEDr2/vcffile/plink_data
I tried this but it copies the whole path: find /40/AD/GWAS_data/Source_Plink/2021_ADGC_EOAD -name "plink_data*" -exec cp --parents {} /target \;
How do I go about doing it? Thanks!
UPDATE: I was able to perform my task with cp using answer from #Cyrus, but not with mv. I thought applying cp and mv in this command would not be any different, but I was wrong. In fact, I needed to use both mv and cp for different tasks, so I resorted to using a loop
for line in $(find . -name "*plink_data*"); do
new_FOLD="$(echo $line| cut -d"." -f2-)"
mkdir -p "NEW_DIR/${new_FOLD}"
cp/mv $line "NEW_DIR/${new_FOLD}"
done
I suggest:
cd /40/AD/GWAS_data/Source_Plink/2021_ADGC_EOAD
mkdir -p NEW_DIR
find . -name "plink_data" -not -path "./NEW_DIR/*" -exec cp --parent {} NEW_DIR \;

Find all files and unzip specific file to local folder

find -name archive.zip -exec unzip {} file.txt \;
This command finds all files named archive.zip and unzips file.txt to the folder that I execute the command from, is there a way to unzip the file to the same folder where the .zip file was found? I would like file.txt to be unzipped to folder1.
folder1\archive.zip
folder2\archive.zip
I realize $dirname is available in a script but I'm looking for a one line command if possible.
#iheartcpp - I successfully ran three alternatives using the same base command...
find . -iname "*.zip"
... which is used to provide the list of / to be passed as an argument to the next command.
Alternative 1: find with -exec + Shell Script (unzips.sh)
File unzips.sh:
#!/bin/sh
# This will unzip the zip files in the same directory as the zip are
for f in "$#" ; do
unzip -o -d `dirname $f` $f
done
Use this alternative like this:
find . -iname '*.zip' -exec ./unzips.sh {} \;
Alternative 2: find with | xargs _ Shell Script (unzips)
Same unzips.sh file.
Use this alternative like this:
find . -iname '*.zip' | xargs ./unzips.sh
Alternative 3: all commands in the same line (no .sh files)
Use this alternative like this:
find . -iname '*.zip' | xargs sh -c 'for f in $#; do unzip -o -d `dirname $f` $f; done;'
Of course, there are other alternatives but hope that the above ones can help.

Remove file in bash with exclude file

I want to remove some file in a directory but '.gitignore' file , I try this command but get an error
[vagrant#lw2 lw2]$ find ./web/assets/* ! -name '.gitignore' | xargs rm -rf
find: `./web/assets/*': No such file or directory
I try again with "." character but I get another error :
[vagrant#lw2 lw2]$ find ./web/assets/. ! -name '.gitignore' | xargs rm -rf
rm: cannot remove directory: `./web/assets/.'
Please tell me what wrong with these command
Thank you !
Try this (for files):
[vagrant#lw2 lw2]$ find /full/path/to/directory/ -type f ! -iname ".gitignore" -exec rm -fv {} \;
or this (for directories):
[vagrant#lw2 lw2]$ find /full/path/to/directory/ -type d ! -iname ".gitignore" -exec rm -fv {} \;
NOTE: Its better to test the command first using temporary directories then run the main command.
You can remove file by file in order to avoid deleting the whole directory and therefore to achieve not deleting the .gitignore
Try this:
find ./web/assets/* -type f ! -name '.gitignore' -exec rm {} \;

Possible to grep and modify/touch the file modification date?

I am using the following to find all instances of a string in a number of files and delete the line where they are found.
find . -maxdepth 1 -xdev -type f -exec sed -i '/teststring/Id' {} \;
I don't want to change the date the file was modified because that impacts on the order that the files are shown in an unrelated application. So I was thinking I could grab the date before executing sed, then touch the file and replace the old modify date at the end of the command. I want to have it all in one command integrated with the above if possible.
Try the following command:
find . -maxdepth 1 -xdev -type f -exec sed -i.bak '/teststring/Id' {} \; -exec touch -r {}.bak {} \; -exec rm {}.bak \;
The find command executes three steps for each file found:
sed changes the file and creates a backup of the original file (with a .bak extension)
touch sets the timestamp of the new file to be the same as the backup
rm deletes the backup
for file in $(find . -maxdepth 1 -xdev -type f )
do
mod_time=$(stat --format=%y $file)
perl -wpl -i -e 's!teststring!!' $file
touch -d ''$mod_time'' $file
done

Resources