How to copy over all files from one directory to another excluding ones that start with a given string in a bash script - linux

I have a directory containing a large amount of files ~1gb. I need to copy over all of them except ones that start with "name" to a different directory. I tried using this: "ls src_folder | grep -v '^name' | xargs cp -t dest_folder" from this pervious question In Linux, how to copy all the files not starting with a given string?
I get the following error when trying to copy over test1.txt from src_folder which contains test1.txt and name.txt to dest_folder
cp: cannot stat `test1.txt': No such file or directory
My current work around is to copy over all of the files, then use find to delete the ones starting with "name" in the dest_folder. This works, but I imagine I could save some time by only copying over the files I really want. Any suggestions?

You can use the shell option extglob. This option extends the bash's pattern matching, so you can use more advanced expressions.
shopt -s extglob
cp src_folder/!(name*) dest_folder
For more info run nam bash and look for extglob.

Related

Is there a grep command that allows me to grep multiple folders and copy them using a text file containing the file names

So I have a text file containing the names of ~1000 folder names, and a directory with around ~30,000 folders. What I need to do is to find a bash command that will read the text file for the folder names, and grep those folders from the directory and copy them to a new destination. Is this at all possible?
I am new to coding, my apologies if this isn't worded well.
you can use a bash scrit like this one:
fileList=$(cat nameFIle)
srcDir="/home/ex/src"
destDir="/home/ex/dest"
for name in fileList
do
cp -r "${srcDir}/${name}" "${destDir}"/
done
Definitely possible - and you don't even need grep. Assuming your text file has one file per line.
cp -r `cat filenames.txt` path_to_copy_location/
I would write:
xargs cp -t /destination/directory < file.of.dirnames

After copying bash directory, edit filenames in new directoy?

I'm currently working on a problem in bash shell to copy a directory to a new one, and that when you check that new directory it will have changed the names of the files it copied. Not sure how to word it exactly so I'll show what it is supposed to output:
-------$ ls -a myproject/
./ ../ file1 file2.c file3.txt .this_is_a_hidden_file
-------$ bkup myproject mybackup
-------$ ls -a mybackup
./ ../ file1-BACKUP file2-BACKUP.c file3-BACKUP.txt
So what happens is that my second parameter in the script bkup copies what is in the first parameter, then edits the names of the files of parameter #1 to add "-BACKUP" between the stem and the extension (eg. between file2 and .c to make file2-BACKUP.c)
I have figured out how to copy the directories using cp -a sourceDir./ destinationDir but how would I edit the file names within destinationDir? Any help is appreciated! Thanks.
Use rename command to rename multiple files using regex, try below
# change directory to the destination folder
$ cd destinationDir
# rename all files
# -n flag will only display how files will be renamed
# once satisfied then remove the -n flag from below command and it will actually rename all files
$ rename -n -v 's/(.+?)(\.[^.]*$|$)/$1-BACKUP$2/' *
You can parameterize the command and include this in your script (bkup)
I am not in front of my Linux box .. so please test and let me know if you see any error.

How do I copy multiple files at once in linux? With the source and the destination locations of these files being the same directory

I have some files located in one directory /home/john
I want to copy all the files with *.text extension from this directory and save them as *.text.bkup, again in the same directory, i.e. /home/john
Is there a single command with which I can do that?
Also, with extension of the same idea, is it possible to copy all the files with multiple extentions (e.g. *.text & *.doc) as *.text.bkup & *.doc.bkup repectively (again in the same directory)?
This is best accomplished with a Shell loop:
~/tmp$ touch one.text two.text three.doc four.doc
~/tmp$ for FILE in *.text *.doc; do cp ${FILE} ${FILE}.bkup; done
~/tmp$ ls -1
four.doc
four.doc.bkup
one.text
one.text.bkup
three.doc
three.doc.bkup
two.text
two.text.bkup
What happens in the code above is the shell gets all .text and .doc files and then loops through each value one by one, assigning the variable FILE to each value. The code block between the "do" and the "done" is executed for every value of FILE, effectively copying each file to filename.bkup.
You can achieve this easily with find:
find /home/john -iname '*.text' -type f -exec cp \{} \{}.backup \;
No, there is no single/simple command to achieve this with standard tools
But you can write a script like this to do it for you.
for file in *.text
do
cp -i "${file}" "${file}.bkup"
done
with -i option you can confirm each overwriting operation
I sort of use a roundabout way to achieve this. It involves a Perl script and needs additional steps.
Step 1:
Copy the names of all the text files into a text file.
find -maxdepth 1 -type f -name '*.txt' > file_name1.txt
Step 2:
Make a duplicate of the copied file.
cp file_name1.txt file_name2.txt
Now open the file_name2.txt in vi editor and do a simple string substitution.
%s/.text/.text.backup/g
Step 3: Merge the source and destination file names into a single file separated by a comma.
paste -d, file_name1.txt file_name2.txt > file_name.txt
Step 4: Run the below perl script to achieve the desired results
open(FILE1,"<file_name.txt") or die'file doesnt exist'; #opens a file that has source and destination separated beforhand using commas
chomp(#F1_CONTENTS=(<FILE1>)); # copies the content of the file into an array
close FILE1;
while()
{
foreach $f1 (#F1_CONTENTS)
{
#file_name=split(/,/,$f1); # separates the file content based on commas
print "cp $file_name[0] $file_name[1]\n";
system ("cp $file_name[0] $file_name[1]"); # performs the actual copy here
}
last;
}

output to a file in script directory

This probably quite basic but I have spent whole day finding an answer without much success.
I have an executable script that resides in ~/Desktop/shell/myScript.sh
I want a single line command to run this script from my terminal that outputs to a new directory in same directory where the script is located no matter what my present working directory is.
I was using:
mkdir -p tmp &&
./Desktop/shell/myScript.sh|grep '18x18'|cut -d":" -f1 > tmp/myList.txt
But it creates new directory in present working directory and not on the target location.
Any help would be appreciated.
Thanks!
You could solve it in one line if you pre-define a variable:
export LOC=$HOME/Desktop/shell
Then you can say
mkdir -p $LOC/tmp && $LOC/myScript.sh | grep '18x18' | cut -d":" -f1 > $LOC/tmp/myList.txt
But if you're doing this repeatedly it might be better long-term to wrap myScript.sh so that it creates the directory, and redirects the output, for you. The grep and cut parameters, as well as the output file name, would be passed as command-line arguments and options to the wrapper.
How about this:
SCRIPTDIR="./Desktop/shell/" ; mkdir "$SCRIPTDIR/tmp" ; "$SCRIPTDIR/myScript.sh" | grep '18x18' | cut -d ":" -f 1 > "$SCRIPTDIR/tmp/myList.txt"
In your case you have to give the path to the script anyway. If you put the script in the path where it is automatically searched, e.g. $HOME/bin, and you can just type myScript.sh without the directory prefix, you can use SCRIPTDIR=$( dirname $( which myScript.sh ) ).
Mixing directories with binaries and data files is usually a bad idea. For temporary files /tmp is the place to go. Consider that your script might become famous and get installed by the administrator in /usr/bin and run by several people at the same time. For this reason, try to think mktemp.
YOUR SCRIPT CAN DO THIS FOR YOU WITH SOME CODES
Instead of doing this manually from the command line and who knows where you will move your script and put it. add the following codes
[1] Find your script directory location using dirname
script_directory=`dirname $0`
The above code will find your script directory and save it in a variable.
[2] Create your "tmp" folder in your script directory
mkdir "$script_directory/tmp 2> /dev/null"
The above code will make a directory called "tmp" in your script directory. If the directory exist, mkdir will not overwrite any existing directory using this command line and gave an error. I hide all errors by "2> /dev/null"
[3] Open your script and modify it using "cut" and then redirect the output to a new file
cat "$0"|grep '18x18'|cut -d":" -f1 > "$script_directory"/tmp/myList.txt

copy multiple files from directory tree to new different tree; bash script

I want to write a script that do specific thing:
I have a txt file e.g.
from1/from2/from3/apple.file;/to1/to2/to3;some not important stuff
from1/from2/banana.file;/to1/to5;some not important stuff
from1/from10/plum.file;/to1//to5/to100;some not important stuff
Now i want to copy file from each line (e.g. apple.file), from original directory tree to new, non existing directories, after first semicolon (;).
I try few code examples from similar questions, but nothing works fine and I'm too weak in bash scripting, to find errors.
Please help :)
need to add some conditions:
file not only need to be copy, but also rename. Example line in file.txt:
from1/from2/from3/apple.file;to1/to2/to3/juice.file;some1
from1/from2/banana.file;to1/to5/fresh.file;something different from above
so apple.file need to be copy and rename to juice.file and put in to1/to2/to3/juice.file
I think thaht cp will also rename file but
mkdir -p "$to"
from answer below will create full folder path with juice.file as folder
In addidtion after second semicolon in each line will be something different, so how to cut it off?
Thanks for all help
EDIT: There will be no spaces in input txt file.
Try this code..
cat file | while IFS=';' read from to some_not_important_stuff
do
to=${to:1} # strip off leading space
mkdir -p "$to" # create parent for 'to' if not existing yet
cp -i "$from" "$to" # option -i to get a warning when it would overwrite something
done
Using awk
(run the awk command first and confirm the output is fine, then add |sh to do the copy)
awk -F";" '{printf "cp %s %s\n",$1,$2}' file |sh
Using shell (get updated that need manually create folder, base on alfe's
while IFS=';' read from to X
do
mkdir -p $to
cp $from $to
done < file
I had this same problem and used tar to solve it! Posted here:
tmpfile=/tmp/myfile.tar
files="/some/folder/file1.txt /some/other/folder/file2.txt"
targetfolder=/home/you/somefolder
tar --file="$tmpfile" "$files"​
tar --extract --file="$tmpfile" --directory="$targetfolder"
In this case, tar will automatically create all (sub)folders for you! Best,
Nabi

Resources