Bash file that creates a directory and subdirectories - linux

I'm new to Bash and have a little program that asks for an input between 1 and 10 and then proceeds to create the same amount of directories the user typed. At the moment my program creates all of the directories in one location, so I'm wondering if there's a way I can create a main folder and then the subdirectories inside one another.
For example:
How many directories would you like to create?
user input: 3
folder1
|-folder2
|-folder3
Any tips on how to get my program to do this will be very much appreciated.
#!/bin/bash
read -p "How many directories would you like?" num_folder
if test $num_folder -lt 10
then
for ((i=0; i<num_folder; i++)); do
mkdir folder$i
done
tree -c
read -rsp "Press enter to continue"
clear
else
echo "Please write a number between 1 and 10"
fi

Another solution maybe the usage of -p parameter with mkdir.
mkdir -p "$(seq -f "folder%0.0f" -s "/" $num_folder)"

how about:
seq 1 3 | xargs mkdir
you can simply use numbers.

Related

creating a new directory each time a shell script is run on linux

I'm trying to create a shell script that copies .log files from one directory to a new directory, with a new name each time the script is run.
For example lets say there's File1.log, File2.log, File3.log in /home/usr/logs
and when this script runs, I want them to be copied to a new location /home/usr/savedlogs/Run1 and the next time it runs.../home/usr/savedlog/Run2 and so on...
I'm not sure if this would be used:
cp /home/usr/logs/{File1.log,File2.log,File3.log} /home/usr/savedlogs
I'm hoping this is possible in a shell script. Thank you all for your help in advance, greatly appreciated!
Here is a simple script that might suffice your requirement:
#!/bin/bash
# Get the number of Run* directories present
newnum=$(ls -ld /home/usr/savedlogs/Run* 2>/dev/null | wc -l)
mkdir -p /home/usr/savedlogs/Run${newnum}
cp /home/usr/logs/*.log /home/usr/savedlogs/Run${newnum}
This will start from Run0 and proceeds from there
If you do not care about incrementing directory names, you can do this with a simple timestamp:
DIR=$(date +%Y%m%d%H%M%S)
mkdir $DIR
cp /home/usr/logs/FileXXX.log /home/usr/savedlogs/$DIR/
This will work as long as your copy operation happens less than once a second.
You may try with newDir=$(ls -l /home/usr/savedlogs | grep Run | wc -l) for getting the existing number of directories.
So the whole script will look like this :
newDir=$(ls -l /home/usr/savedlogs | grep Run | wc -l)
mkdir -p /home/usr/savedlogs/Run${newDir}
cp /home/usr/logs/*.log /home/usr/savedlogs/Run${newDir}
First folder will be Run0, next Run1 and so on...

prompt list of files before execution of rm

I started using "sudo rm -r" to delete files/directories. I even put it as an alias of rm.
I normally know what I am doing and I am quite experience linux user.
However, I would like that when I press the "ENTER", before the execution of rm, a list of files will show up on the screen and a prompt at the end to OK the deletion of files.
Options -i -I -v does not do what I want. I want only one prompt for all the printed files on screen.
Thank you.
##
# Double-check files to delete.
delcheck() {
printf 'Here are the %d files you said you wanted to delete:\n' "$#"
printf '"%s"\n' "$#"
read -p 'Do you want to delete them? [y/N] ' doit
case "$doit" in
[yY]) rm "$#";;
*) printf 'No files deleted\n';;
esac
}
This is a shell function that (when used properly) will do what you want. However, if you load the function in your current shell then try to use it with sudo, it won't do what you expect because sudo creates a separate shell. So you'd need to make this a shell script…
#!/bin/bash
… same code as above …
# All this script does is create the function and then execute it.
# It's lazy, but functions are nice.
delcheck "$#"
…then make sure sudo can access it. Put it in some place that is in the sudo execution PATH (Depending on sudo configuration.) Then if you really want to execute it precisely as sudo rm -r * you will still need to name the script rm, (which in my opinion is dangerous) and make sure its PATH is before /bin in your PATH. (Also dangerous). But there you go.
Here's a nice option
Alias rm to echo | xargs -p rm
The -p option means "interactive" - it will display the entire command (including any expanded file lists) and ask you to confirm
It will NOT ask about the recursively removed files. But it will expand rm * .o to:
rm -rf * .o
rm -rf program.cc program.cc~ program program.o backup?... # NO NO NO NO NO!
Which is much nicer than receiving the error
rm: .o file not found
Edit: corrected the solution based on chepner comment. My previous solutions had a bug :(
This simple script prompts for a y response before deleting the files specified.
rmc script file:
read -p "ok to delete? " ans
case $ans in
[yY]*) sudo rm "$#" ;;
*) echo "Nothing deleted";;
esac
Invoke thus
./rmc *.tmp
I created a script to do this. The solution is similar to #kojiro's.
Save the script with the filename del. Run the command sudo chmod a=r+w+x del to make the script an executable. In the directory in which you want to save the script, export the path by entering export PATH=$PATH:/path/to/the/del/executable in your '~/.bashrc' file and run source ~/.bashrc.
Here, the syntax of rm is preserved, except instead of typing rm ..., type del ... where del is the name of the bash script below.
#! /bin/bash
# Safely delete files
args=("$#") # store all arguments passed to shell
N=$# # number of arguments passed to shell
#echo $#
#echo $#
#echo ${args[#]:0}
echo "Files to delete:"
echo
n=`expr $N - 1`
for i in `seq 0 $n`
do
str=${args[i]}
if [ ${str:0:1} != "-" ]; then
echo $str
fi
done
echo
read -r -p "Delete these files? [y/n] " response
case $response in
[yY][eE][sS]|[yY])
rm ${args[#]:0}
esac

linux checking number of files subdirectory - providing wrong variable result when subdirectory searching for does not exist

I have created a script that goes through specific subdirectories of files and tells me how many files are in each sub-directory that start with s. My problem occurs when it is searching and the sub-directory has failed to be created. For some reason, when the sub-directory that this script is searching for does not exist, it replaces the output with another previously created variable????
I am writing this in bash for linux.
I am looking at the following subdirectories...
participantdirectory/EmotMRI
participantdirectory/EmotMRI/firstfour/
participantdirectory/T1
So, this is the output I should get, when the subdirectory exists and everything is ok. It is the same for all files (if it is correct).
/home/orkney_01/jsiegel/ruth_data/participants/analysis2/1206681446/20090303/14693
16 in firstfour
776 in EmotMRI folder
2 files in T1 folder
For a directory which does not have a subdirectory created, I get this output...
bash: cd: /home/orkney_01/jsiegel/ruth_data/participants/analysis2/2102770508/20090210 /14616/EmotMRI/firstfour/: No such file or directory
/home/orkney_01/jsiegel/ruth_data/participants/analysis2/2102770508/20090210/14616
776 in firstfour
114 in EmotMRI folder
2 files in T1 folder
I think that, because firstfour is a subdirectory of EmotMRI, when firstfour folder hasn't been created, it substitutes the scan numbers in EmotMRI for this answer? The number of scans in EmotMRI (in this instance is correct). Here is my script below. If this is happening, how do I stop it from doing this?
for d in $(cat /home/orkney_01/jsiegel/ruth_data/lists/full_participant_list_location_may20)
do
if [ -d "$d" ]
then
gr="failed"
er="failed"
fr="failed"
cd $d/EmotMRI/firstfour/
gr=$(ls s*| wc -l)
echo " "
echo "$d"
echo "$gr in firstfour"
cd $d/EmotMRI/
er=$(ls s*| wc -l)
echo "$er in EmotMRI folder"
cd $d/T1/
fr=$(ls s*| wc -l)
echo "$fr files in T1 folder"
cd $d/EmotMRI
else
echo "$d is currently not available in directory"
fi
done
cd /home/orkney_01/jsiegel/ruth_data/
echo "Check complete"
I know you will probably have many improvements on this script, I am very new to linux. Thanks for your help,
Currently, you set gr to the output of ls s* | wc -l regardless of whether you successfully change your working directory. When that cd fails, it leaves you in whatever directory you were in previously.
You can combine your cd command into your other commands to set gr:
gr=$(cd $d/EmotMRI/firstfour/ && ls s* | wc -l || echo failed)
This way, if you successfully cd into the subdirectory, gr will be set to the output of the commands after &&. Otherwise, gr will be set to the output of the command after the ||. You can do the same thing with er and fr.
You are getting error messages that you shoud fix. Cd is failing because you are not allowed to change into a non-existent directory. Your shell will just stay in the directory it was in. It looks like you know how to test for directory existence, so you should just do that more to avoid trying to go into non-existent directories.

Remove in linux

hey so I have some code for the question bellow but I am stuck its not working and I don't really know what I am doing.
This script should remove the contents of the dustbin directory.
If the -a option is used the script should remove ALL files from the dustbin.
Otherwise, the script should display the filenames in the dustbin one by one and ask the user for confirmation that they should be deleted
#!/bin/sh
echo " The files in the dustbin are : "
ls ~/TAM/dustbin
read -p " Please enter -a to delete all files else you will be prompted to delete one by one : " filename
read ans
if ["filename" == "-a"]
cat ~/TAM/dustbin
rm -rf*
else
ls > ~/TAM/dustbin
for line in `cat ~/TAM/dustbin`
do
echo "Do you want to delete this file" $line
echo "Y/N"
read ans
case "ans" in
Y) rm $line ;;
N) "" ;;
esac
EDITED VERSION
if test ! -f ~/TAM/dustbin/*
then
echo "this directory is empty"
else
for resfile in ~/TAM/dustbin/*
do
if test -f $resfile ; then
echo "Do you want to delete $resfile"
echo "Y/N"
read ans
if test $ans = Y ; then
rm $resfile
echo "File $resfile was deleted"
fi
fi
done
fi
this works however Now I get one of 2 errors either
line 4 requires a binary operator or line 4: to many arguments
I see one obvious mistake:
rm -rf*
when it should be
rm -rf *
to be asked about every file deletion - add -i key
rm -rfi *
Many problems here:
A space missing before the * in rm. The space is needed so the shell can recognize the wildcard and expand it.
Do you really want to remove all the files in the current directory? If not, specify the path rm -rf /path/to/files/* or cd into the directory, preferably with cd /path/to/files || exit 1.
I do not understand the logic of the script. You show a dustbin, but if the user gives -a, you overwrite it with all the non-hidden files (ls > dustbin). Is that what you want?
First of all, case "ans" of just matches a string "ans" to other strings, which is obviously false, you need case $ans of to get the value of variable ans. if ["filename" == "-a"] is also comparison between two strings, which is always false. The first parameter of a script can be accessed as $1 (the second as $2 and so on).
Please read man 1 sh to get the basics of shell programming (all of the above notes can be found there).

launch process in background and modify it from bash script

I'm creating a bash script that will run a process in the background, which creates a socket file. The socket file then needs to be chmod'd. The problem I'm having is that the socket file isn't being created before trying to chmod the file.
Example source:
#!/bin/bash
# first create folder that will hold socket file
mkdir /tmp/myproc
# now run process in background that generates the socket file
node ../main.js &
# finally chmod the thing
chmod /tmp/myproc/*.sock
How do I delay the execution of the chmod until after the socket file has been created?
The easiest way I know to do this is to busywait for the file to appear. Conveniently, ls returns non-zero when the file it is asked to list doesn't exist; so just loop on ls until it returns 0, and when it does you know you have at least one *.sock file to chmod.
#!/bin/sh
echo -n "Waiting for socket to open.."
( while [ ! $(ls /tmp/myproc/*.sock) ]; do
echo -n "."
sleep 2
done ) 2> /dev/null
echo ". Found"
If this is something you need to do more than once wrap it in a function, but otherwise as is should do what you need.
EDIT:
As pointed out in the comments, using ls like this is inferior to -e in the test, so the rewritten script below is to be preferred. (I have also corrected the shell invocation, as -n is not supported on all platforms in sh emulation mode.)
#!/bin/bash
echo -n "Waiting for socket to open.."
while [ ! -e /tmp/myproc/*.sock ]; do
echo -n "."
sleep 2
done
echo ". Found"
Test to see if the file exists before proceeding:
while [[ ! -e filename ]]
do
sleep 1
done
If you set your umask (try umask 0) you may not have to chmod at all. If you still don't get the right permissions check if node has options to change that.

Resources