copying files to another folder using bash - bash

I have a script that copies 1000 files to another folder. However, I have files that end with the following:
*_LINKED_1.trees
*_LINKED_2.trees
*_LINKED_3.trees
.
.
.
*_LINKED_10.trees
'*' is not part of the name but there's some string in place of it.
What I want is to copy 1000 files for each of the types I've mentioned above in bullet points in a smart way.
#!/bin/bash
for entry in /home/noor/popGen/sweeps/hard/final/*
do
for i in {1..1000}
do
cp $entry /home/noor/popGen/sweeps/hard/sample/hard
done
done
Could there be a smart way to copy all 1000 files for each type? One way would be to have an if statement but I'll have to change that if- statement 10 times.

This script below will do the required task.
file_count=0
for i in {1..10};
do
for j in source/*_LINKED_$i.trees;
do
file_count=$((file_count+1))
echo "cp $j destination/"
if ((file_count>1000));
then
file_count=0
break;
fi;
done
done
Outer loop for i in {1..10} is used to mark the type of the files (*_LINKED_$i.trees).
Inner loop will iterate through all the files of each type (eg: *_LINKED_1.trees, *_LINKED_2.trees etc till *_LINKED_10.trees). Then it copies the first 1000 files (set using file_count=1000) into the destination for that particular type of file.

Related

Create infinite number of nested folders using infinite loop

I am working on a small project. The task is to create a bash script that will create infinite number of folders when clicked, and inside each folder, it creates infinite number of folders in each folder and so on. For example,
Folder1
SubFolder1
SubFolder2
SubFolder3
...
SubFolder∞
SubSubFolder1
SubSubFolder2
SubSubFolder3
...
SubSubFolder∞
SubSubSubFolder1
SubSubSubFolder2
SubSubSubFolder3
...
SubSubSubFolder∞
...
Folder∞
SubFolder1
SubFolder2
SubFolder3
...
SubFolder∞
SubSubFolder1
SubSubFolder2
SubSubFolder3
...
SubSubFolder∞
SubSubSubFolder1
SubSubSubFolder2
SubSubSubFolder3
...
SubSubSubFolder∞
The sequence is like this:
Folder 1 has infinite folders (SubFolder1, SubFolder2, ..., SubFolder∞). The first folder(SubFolder1) has further sub folders (SubSubFolder1, ..., SubSubFolder∞). The SubSubFolder1 has further subfolders (SubSubSubFolder1, ... SubSubSubFolder∞) and so on. Similar for Folder2 and its sub folders.
I tested the script for 10 folders. It created 10 top-level folders. In each folder, it created 10 subfolders each. But it stopped there, I want it to run continuously (infinite loop). Also, it works sequentially (it will create 10 subfolders in Folder1, then comeout and create Folder2, and its sub folders and so on), I want it continuous (make Folder1 and its subfolders continuously with Folder2 and its subfolders and so on). The code:
#!/bin/bash
# Set the number of outer and inner directories to create
num_outer=10
num_inner=10
# Create the outer loop
for ((i=0; i<num_outer; i++))
do
# Create a new outer directory with a unique name
mkdir "outer_folder_$i"
# Navigate into the new outer directory
cd "outer_folder_$i"
# Create the inner loop
for ((j=0; j<num_inner; j++))
do
# Create a new inner directory with a unique name
mkdir "inner_folder_$j"
done
# Navigate back to the parent directory
cd ..
done
This rekfolder.sh script does not produce an infinite number of directories, because the constant flow of new harddrives would be too expensive for me, but about x! (x fac) numbers of directories, where x is is given as a command line parameter and counted downwards in each recursive step.
Start it like this:
timeout -k 5 3s ./rekfolder.sh f 8
which stops the script after 3s and - if things go wrong - kills it after 5. f will be the name part of the starting dir.
#!/bin/bash
name=$1
count=$2
# save my harddrive!
if (( ${#name} > 25 ))
then
echo err namelength
exit 0
elif (( count == 0 ))
then
echo err count
exit 0
else
# Set the number of directories to create
num=3
name=$name
for ((i=0; i<count; i++))
do
# save my harddrive again
sleep 0.3
echo mkdir ${name}$i
mkdir ${name}$i
./rekfolder.sh ${name}$i/ $((count-1)) &
done
fi
This produced 109600 directories. The sleep is in there, to allow to interrupt the process of exponential growth with a killall rekfolder.sh in a second terminal, but it's getting hard, if you don't interrupt early.
You may delete all those folders, if they are created in a fresh dir, with
find -type d -delete
(took me about a second (SSD)).
Note that there is much trailing output, long after finishing all the ./rekfolder.sh scripts, which makes it look, as if the timeout does not work. You may observe the processes in a second terminal
for i in {1..10}
do
ps -C rekfolder.sh
sleep 1
done

How to create a list of sequentially numbered folders using an existing folder name as the base name

I've done a small amount of bash scripting. Mostly modifying a script to my needs.
On this one I am stumped.
I need a script that will read a sub-folder name inside a folder and make a numbered list of folders based on that sub-folder name.
Example:
I make a folder named “Pictures”.
Then inside I make a sub-folder named “picture-set”
I want a script to see the existing sub-folder name (picture-set) and make 10 more folders with sequential numbers appended to the end of the folder names.
ex:
folder is: Pictures
sub-folder is: picture-set
want to create:
“picture-set-01”
“picture-set-02”
“picture-set-03”
and so forth up to 10. Or a number specified in the script.
The folder structure would look like this:
/home/Pictures/picture-set
/home/Pictures/picture-set-01
/home/Pictures/picture-set-02
/home/Pictures/picture-set-03
... and so on
I am unable to tell the script how to find the base folder name to make additional folders.
ie: “picture-set”
or a better option:
Would be to create a folder and then create a set of numbered sub-folders based on the parent folder name.
ex:
/home/Songs - would become:
/home/Songs/Songs-001
/home/Songs/Songs-002
/home/Songs/Songs-003
and so on.
Please pardon my bad formatting... this is my first time asking a question on a forum such as this. Any links or pointers as to proper formatting is welcome.
Thanks for the help.
Bash has a parameter expansion you can use to generate folder names as arguments to the mkdir command:
#!/usr/bin/env bash
# Creates all directories up to 10
mkdir -p -- /home/Songs/Songs-{001..010}
This method is not very flexible if you need to dinamically change the range of numbers to generate using variables.
So you may use a Bash for loop and print format the names with desired number of digits and create each directory in the loop:
#!/usr/bin/env bash
start_index=1
end_index=10
for ((i=start_index; i<=end_index; i++)); do
# format a dirpath with the 3-digits index
printf -v dirpath '/home/Songs/Songs-%03d' $i
mkdir -p -- "$dirpath"
done
# Prerequisite:
mkdir Pictures
cd Pictures
# Your script:
min=1
max=12
name="$(basename "$(realpath .)")"
for num in $(seq -w $min $max); do mkdir "$name-$num"; done
# Result
ls
Pictures-01 Pictures-03 Pictures-05 Pictures-07 Pictures-09 Pictures-11
Pictures-02 Pictures-04 Pictures-06 Pictures-08 Pictures-10 Pictures-12

How to iterate between directories in shell script

I want to convert images from .img to .nii.gz using the function fslchfiletype.
These images are stored in Controls and Patients folders, each one of this folders have several folders belonging to each one of the individuals, like C01, C02, , etc. Specifically, each one of the individuals has the .img files inside a folder called rs_roi, which is inside another folder called ROIS2. This is what I have:
DIR="/media/Roy"; cd "$DIR/Analysis"
for group in Controls Patients; do
for case in $group; do
mkdir $DIR/Analysis/$group/$case/Cortical_masks
for file in $DIR/Analysis/$group/$case/ROIS2/rs_roi/.img; do
fslchfiletype NIFTI_GZ "$file"
done;
done;
done;
Notice how I also want to create a folder called Cortiical_maks inside each and one of the individuals.
This gives me the next error:
mkdir: cannot create directory ´media/Roy/Analysis/Controls/Controls/Cortical_masks´: No such file or directory.
Cannot open volume media/Roy/Analysis/Controls/Controls/ROIS2/rs_roi/ for reading!
mkdir: cannot create directory ´media/Roy/Analysis/Patients/Patients/Cortical_masks´: No such file or directory.
Cannot open volume media/Roy/Analysis/Patients/Patients/ROIS2/rs_roi/ for reading!
It´s iterating two times the Controls Patients folder: Control/Control. Maybe the problem is here for case in $group; do? Thx
Once you have your directory name assigned to a variable, you have to glob the directory to get its contents. Otherwise, as you saw, $group is not expanded, and you're only looping over that single term itself.
You might also like to check that each entry is indeed a directory before you traverse into it.
for case in $group/*; do
[ -d $case ] || continue
mkdir $DIR/Analysis/$group/$case/Cortical_masks
for file in $DIR/Analysis/$group/$case/ROIS2/rs_roi/.img; do
fslchfiletype NIFTI_GZ "$file"
done;
done;
You should probably also quote your variables in more places, unless you are sure they don't need quoting. I always lint my scripts with shellcheck to get that kind of advice.
I made a small change to #Noah answer, this script works fine:
for group in Controls Patients; do
for case in $group/*; do
[ -d $case ] || continue
mkdir $DIR/Analysis/$case/Cortical_masks
for file in $DIR/Analysis/$case/ROIS2/rs_roi/*.img; do
fslchfiletype NIFTI_GZ "$file"
done;
done;
done;
I deleted $group in both paths, and added * in *.img which i forgot.

How to recursively rename all files and folder including specific part of the filename with Windows Bash?

This has to be a duplicate but I have read and tried at least a dozen of Q&As here on SO, and I cannot get any of them working for my case.
Really hope this won't result in downvotes because of it.
So I'm on Windows (10) and have a Bash terminal that I want to use for my task. The MINGW64 one I downloaded when I started working with Git.
I would prefer the solution with this program, but will be perfectly happy with one in Command Prompt Terminal or even PowerShell.
I created a TemplateApp which is in C:\Apps\TemplateApp folder which has multiple folders and subfolders named TemplateApp or TemplateApp.something as well as a lot of files that have TemplateApp as a part of their name.
Could be:
TemplateApp.ext
TemplateApp.something.ext
something.TemplateApp.something.ext
Then I copied the uppermost folder to C:\Apps\TemplateApp - Copy and in turn renamed it to C:\Apps\ProductionApplication.
Now for the love of whomever, I cannot make any of the scripts I found on SO to work for my case, ie. to rename all the above mentioned files and folders by replacing TemplateApp with ProductionApplication.
Here is a bash function I wrote that I think does very much like what you are wanting to do.
function func_CreateSourceAndDestination() {
#
for (( i = 0 ; i < ${#files_syncSource[#]} ; i++ )) ; do
files_syncDestination[${i}]="${files_syncSource[${i}]#${directory_MusicLibraryRoot_source}}"
file_destinationPath="$( dirname -- "${directory_PMPRoot_destination}${files_syncDestination[${i}]}" )"
if [ ! -d "${file_destinationPath}" ] ; then
mkdir -p "${file_destinationPath}"
fi
rsync -rltDvPmz "${files_syncSource[${i}]}" "${directory_PMPRoot_destination}${files_syncDestination[${i}]}"
done
}
In my case I'm feeding into rsync for a source and a destination. I'm pulling all the file paths from an array that has been split into path segments. I have to make certain character substitutions for FAT and NTFS file systems. I do this recursively.
files_syncDestination[${i}]="${files_syncDestination[${i}]//\:/__}"
That's the magic. I load a new array with the character substituted. You could do the same with a loaded variable including your phrases for change.
files_syncDestination[${i}]="${files_syncDestination[${i}]//${targetPhrase}/${subPhrase}}"
After that change in the function, you could use rsync or cp or mv as you prefer to go from your source array to your destination array.
(The double-slash in the substitution makes the substitution global.)

Nesting a case statement within a for loop

I'm trying to follow the instructions below in order to create one directory containing four subdirectories inside, each of these latter with five new empty files:
Create a directory with the name of the first positional parameter (choose whatever name you want).
Use a for loop to do the following:
2.1. Within the directory, create four subdirectories with these names: rent, utilities, groceries, other.
2.2. Within the for loop, use case statements to determine which subdirectory is currently being handled in the loop. You will need 4
cases.
2.3. Within each case, use a for loop to create 5 empty files with the touch command. Each subdirectory must have its 5 files inside.
So far, I have created a directory and several subdirectories at once, each of them with a specific name, as you can see in my code:
mkdir $1
for folder in $1; do
mkdir -p $1/{Rent,Utilities,Groceries,Other}
done
However, I'm stuck in the following step (2.2.), and I don't know how to continue from here.
Any ideas?
As I read it, this is what 2.1 and 2.2 are asking for:
for folder in rent utilities groceries other; do
mkdir "$1/$folder"
case $folder in
rent)
...
;;
utilities)
...
;;
groceries)
...
;;
other)
...
;;
esac
done
I've left the cases blank for you to fill out.
For what it's worth, I would never code a script this way. Having a case statement inside a for loop is an anti-pattern. The loop really adds no value. If this weren't an assignment I would code it differently:
mkdir "$1"
# Populate rent/ directory.
mkdir "$1"/rent
touch "$1"/rent/...
# Populate utilities/ directory.
mkdir "$1"/utilities
touch "$1"/utilities/...
# Populate groceries/ directory.
mkdir "$1"/groceries
touch "$1"/groceries/...
# Populate other/ directory.
mkdir "$1"/other
touch "$1"/other/...

Resources