How to get a list of subdirectories from a file and then create those subdirectories in a directory? - bash

When a user inputs a name, there should be a new directory that gets created under that name.
In addition to that, the script needs to consult a file structure1.txt which is found in /etc/scriptbuilder/str1.
In this file, it will list two subdirectories (one on each line), the script is then supposed to create these two subdirectories in the new directory the user just made and named.
So how can the script then create each of the subdirectories that are listed in this text file?
I'm completely lost on that part.
This is my code so far:
echo "Enter the project name "
read name
echo $name
if [ ! -d $name ] then
mkdir $name
else
echo "The project name you entered already exists"
fi
cp /etc/scriptbuilder/str1/structure1.txt /$name
#I know this is wrong
because this would just copy the file over to the new directory but not actually
make the two subdirectories that are on the file onto the new directory

The bash command that you are looking for is read.
Also the syntax for your if [ ! -d "$name" ] should have a semicolon.
The else would typically have an exit 1 (or some such value).
Typical bash code gets input from the command line, but what you want is fine.
For testing purposes, I inserted a ~ (tilde), which references your home directory.
The script should look something like:
filename="/etc/scriptbuilder/str1"
read -p "Enter the project name " name
echo "$name"
if [ ! -d ~/"$name" ]; then
mkdir ~/"$name"
else
echo "The project name you entered already exists"
exit 1
fi
while read -r line; do
mkdir ~/"$name/$line"
done < "$filename"
You can clean up the formatting.

Related

Is there a way I can take user input and make it into a file?

I am not able to find a way to make bash create a file with the same name as the file the user dragged into the terminal.
read -p 'file: ' file
if [ "$file" -eq "" ]; then
cd desktop
mkdir
fi
I am trying to make this part of the script take the name of the file they dragged in so for example /Users/admin/Desktop/test.app cd into it copy the "contents" file make another folder with the same name so test.app for this example and then paste the contents file into that folder and delete the old file.
From your .app example, I assume you are using MacOS. Therefore you will need to test this script yourself since I don't have MacOS, but I think it should be doing what you want. Execute it as bash script.sh and it will give you your desired directory test.app/contents in the current working directory.
#! /bin/bash
read -rp 'file: ' file
if [ -e "$file" ]; then
if [ -e "$file"/contents ]; then
base=$(basename "$file")
mkdir "$base"
cp -R "$file"/contents "$base"
rm -rf "$file"
else
echo "The specified file $file has no directory 'contents'."
fi
else
echo "The specified file $file does not exist."
fi

How do I combine an "if" and a "while loop" statement together?

New to shell scripting and I want to test to see if the variables I created are valid directories and if not send the user into a while loop to enter the directory and only allow exit when a valid directory is entered.
So far this is what my script looks like:
~/bin/bash
source_dir="$1"
dest_dir="$2"
mkdir /#HOME/$source_dir
mkdir /#HOME$dest_dir
if [ -d "$source_dir" ]
then
echo "$source_dir is a valid directory"
fi
while [[ ! -d "$source_dir" ]]
do
echo "Please enter a valid directory"
read source_dir
done
Is there any way to combine these into a single statement?
The while code will never execute if the directory is valid. Therefore just move the echo "$source_dir is a valid directory" after the loop:
#!/bin/bash
source_dir="$1"
dest_dir="$2"
mkdir "$HOME/$source_dir"
mkdir "$HOME/$dest_dir"
until [[ -d "$source_dir" ]]
do
read -p "Please enter a valid directory" source_dir
done
echo "$source_dir is a valid directory"
Notes:
a few code typos were fixed, e.g. /#HOME$dest_dir should be "$HOME/$dest_dir".
any while ! can be shortened to until.
The above code lacks a few things:
It tries create a new dir, then if that fails, has the user enter an already existing directory. It might be better to let the user create a new directory, but only if it doesn't already exist.
It would be better to check if $dest_dir exists.
Here's a more thorough approach using a shell function:
#!/bin/bash
untilmkdir ()
{
d="$1";
until mkdir "$d" ; do
read -p "Please enter a valid directory: " d
[ -d "$d" ] && break
done;
echo "$d is a valid directory" 1>&2
echo "$d"
}
source_dir=$(untilmkdir "$HOME/$1")
dest_dir=$(untilmkdir "$HOME/$2")
Notes:
The prompts in untilmkdir are printed to stderr.
The name of whatever directory untilmkdir creates is printed to stdout.
Having untilmkdir print to both stderr and stdout allows storing the successfully created name to a variable.

Linux shell script to copy and rename multiple files

I have this snippet:
#!/bin/bash
parent=/parent
newfolder=/newfolder
mkdir "$newfolder"
for folder in "$parent"/*; do
if [[ -d $folder ]]; then
foldername="${folder##*/}"
for file in "$parent"/"$foldername"/*; do
filename="${file##*/}"
newfilename="$foldername"_"$filename"
cp "$file" "$newfolder"/"$newfilename"
done
fi
done
I do need to turn it around in a way that the copied files would be named after the folder they are being moved to (e.g. moving to the /root/Case22 files would be renamed to case22_1.jpg, case22_2.docx, case22_3.JPG etc). The files would be copied from USB and both destination and source directries would be entered by the user. I have written everything else and it works apart from actual renaming and thought I could adapt this snippet.
thanks
p.s. the snippet is written by Jahid and found on stackoverflow
you can try something like this;
#!/bin/bash
parent=/root
a=1
for file in $parent/Case22*; do
filename="${file%.*}"
extension="${file##*.}"
newfilename=$(printf "$filename"_"$a"."$extension")
mv -- "$file" "$newfilename"
let a=a+1
done
Thanks for the help. I have found the solution and thought I might post it here in case someone else will be looking at this.
As the title suggests I needed a Linux shell script to copy and rename multiple files keeping original directory tree (the file source and archive locations would be specified by the user of the script). Here is the code that I came up with after few days research of different sources (it includes a trap so only one instance of script would be running at a time):
lockdir=/var/tmp/mylock #directory for lock file creation
pidfile=/var/tmp/mylock/pid #directory to get the process ID number
if ( mkdir ${lockdir} ) 2> /dev/null; then #main argument to create lock file
echo $$ > $pidfile #if successful script will proceed, otherwise it will skip to the else part of the statement at the end of the script
trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT #trap to capture reasons of script termination and removal of the lock file so it could be launched again
#start of the main script body, part of successful "if" statement
# read entry_for_testing_only #request for user entry to keep script running and try to run another script instance
findir="$2/$(basename "$1")" #variable that defines final directory to which files from USB will be copied
if [ ! -d "$1" ]; then #testing if first directory entry is a valid directory’’
echo "$1" "is not a directory"
echo ""
exit
else
if [ ! -d "$2" ]; then #testing if second entry is a valid directory
echo "archive directory non existant"
exit
else
if [ -d "$findir" ] && [ "$(ls -A "$findir")" ]; then #testing if second entry directory contains the same name folders and if the folders are empty - to avoid file overwriting
echo "such folder already there and it's not empty"
exit
else
if [ ! -d "$findir" ] ; then #last archive directory argument to create final archive directory
mkdir "$findir"
else true
fi
fi
fi
fi
rsync -a "$1"/ "$findir" #command to copy all files from the source to the archive retaining the directory tree
moved_files="$(find "$findir" -type f)" #variable that finds all files that have been copied to the archive directory
for file in $moved_files; do #start of the loop that renames copied files
counter="$((counter+1))" #incrementation variable
source_name="$(basename "$1")" #variable that captures the name of the source directory
new_name="$source_name"_"$counter" #variable that puts start of the file name and incrementation element together
if echo "$file" | grep "\." #argument that captures the extension of the file
then
extension="$(echo "$file" | cut -f2 -d. )"
else
extension=
fi
full_name="$new_name"."$extension" #variable that defines the final new name of the file
dir="$(dirname "${file}")" #variable that captures the directorry address of currently looped file
mv "$file" "$dir/$full_name" #move command to rename currently looped file with the final new name
done
#end of the main script body, unsuccessful "if" statement continues here
else
echo "Another instance of this script is already running. PID: $(cat $pidfile)"
fi

Shell Script to copy all files in a directory to a specified folder

I'm new in shell script and I am trying to figure out a way to write a script that copies all the files in the current directory to a directory specified from a .txt file and if there are matching names, it adds the current date in the form of FileName_YYYYMMDDmmss to the name of the file being copied to prevent overwritting.
Can someone help me out?
I saw thinking something along the lines of
#!/bin/bash
source=$pwd #I dont know wheter this actually makes sense I just want to
#say that my source directory is the one that I am in right now
destination=$1 #As I said I want to read the destination off of the .txt file
for i in $source #I just pseudo coded this part because I didn't figure it out.
do
if(file name exists)
then
copy by changing name
else
copy
fi
done
the problem is I have no idea how to check whether the name exist and copy and rename at the same time.
Thanks
How about this? I am supposing that the target directory is in the
file new_dir.txt.
#!/bin/bash
new_dir=$(cat new_dir.txt)
now=$(date +"%Y%m%d%M%S")
if [ ! -d $new_dir ]; then
echo "$new_dir doesn't exist" >&2
exit 1
fi
ls | while read ls_entry
do
if [ ! -f $ls_entry ]; then
continue
fi
if [ -f $new_dir/$ls_entry ]; then
cp $ls_entry $new_dir/$ls_entry\_$now
else
cp $ls_entry $new_dir/$ls_entry
fi
done
I guess this what you are looking for :
#!/bin/bash
dir=$(cat a.txt)
for i in $(ls -l|grep -v "^[dt]"|awk '{print $9}')
do
cp $i $dir/$i"_"$(date +%Y%m%d%H%M%S)
done
I assumed that a.txt contains only the name of the destination directory. If there are other entries, you should add some filter to the first statement(using grep or awk).
NB: I used full time stamp(YYYYMMDDHHmmss) instead of your YYYYMMDDmmss as it doesn't seem logical.

making a menu-driven interface that can read a list of files and delete them

I'm working on a shell script which is a menu-driven interface.
one of the options asks user to enter a list of optional files or directories and then the code will delete them after checking if they are valid files and directories.
the goal of the code is understanding of menu-driven interface.
my problem is reading the list of files and directory names.
It seems that sh does not support array. what is the solution for this problem?
2) echo "enter the name of files want to be deleted: "
read files
.
.
;;
2) echo "enter the name of files want to be deleted"
read a
for CHARACTER in $a ; do
if [ -f $CHARACTER -o -d $CHARACTER ] ; then
rm -ir $CHARACTER
else
echo "$CHARACTER is not a valid file or directory"
fi
done
;;

Resources