Create folders at same time in bash - linux

I need to create a number of folders with the same name but with a number at the end.
User should write a number and the script should create these numbers of folders. I don't know how to link the number and the number os folders.
Here is my script
#!/bin/bash
echo "(1617S2)" A.C.B.S
pwd
date
NOM="A.C.B.S"
echo $NOM
echo -n "Introduce el numero de carpetas que quieras :"
read x
if (($x<=10)); then
echo "Son $x carpetas"
else (($ <10))
echo -n "El número de carpetas tiene que ser entre 1 i 10 :"
read x2
echo "Son $x2 carpetas"
fi
cd ..
cd /var
sudo mkdir carpetaprincipal
cd ..
cd /var/carpetaprincipal
sudo mkdir carpeta {1..10}

You could use seq with xargs to iterate and create the number of folders chosen for the input:
#!/bin/bash
echo "(1617S2)" A.C.B.S
pwd ; date
NOM="A.C.B.S" ; echo $NOM
function makeFolders () {
echo -n "Introduce el numero de carpetas que quieras :"
read -r x
if [[ "$x" -lt 11 ]] && [[ "$x" -gt 0 ]]; then
echo "Son $x carpetas"
cd ../var || exit
mkdir carpetaprincipal
cd carpetaprincipal || exit
seq "$x" | xargs -I{} mkdir carpeta_{}
fi
if [[ "$x" -lt 1 ]] || [[ "$x" -gt 10 ]]; then
echo "El número de carpetas tiene que ser entre 1 i 10!"
makeFolders # you could optionally exit 1 here
fi
}
makeFolders
There were some other issues with your script, mainly the logic didn't make sense. If you put in more than 10 or less than 1 then the script still allowed the user to create folders which are above are below what is supposed to be allowed. Putting those methods within in a function also allows you to return to the input line if there is an error. Also, read should include -r, otherwise it has the potential to mangle backslashes.

To do multiple mkdir while looping a variable number of times:
x2=4
i=1
while [ "$i" -le "$x2" ]
do
sudo mkdir carpeta$1
i=$(($i + 1))
done

Related

Why my code don't understand when I close the for loop?

I am writing a code in Shell Script trying to automatize some procedures in my data processing, but I facing some problems concerning the for. The code is the following. And it seems like he is understanding that I already closed the for loop.
#!/bin/bash
#modelos que serão usados
models=( 410_5x5_nocrust ) # 660_5x5_nocrust mtz_2x2_nocrust mtz_5x5_nocrust mtz_8x8_nocrust mtz_11x11_nocrust prem_nocrust prem s40rts_nocrust 660_5x5_s40rts_nocrust tx2015_nocrust)
#pasta base de onde todos os arquivos e programas estão
home_folder=/home/felipe/sda1_acess/RF_PROCESSING
for i in $models
do
#criando as pastas importantes para o trabalho
if ( ! -e $PWD/Listas )
then
mkdir $PWD/Listas
fi
if ( ! -e $PWD/Listas/"$i"_lists )
then
mkdir $PWD/Listas/"$i"_lists
fi
if ( ! -e $PWD/sacev )
then
mkdir $PWD/sacev
if
if ( ! -e $PWD/sacev/sacev_$i )
then
mkdir $PWD/sacev/sacev_$i/
fi
#setando a pasta onde os arquivos estão
folder=XH_preprocessed_"$i"_stations_1x1_RF_8s
#acessando a pasta
cd $home_folder/$folder
#numero de eventos q temos por modelo
v=(01 02) #03 04 05 06 07 08 09 10 11 12)
#Fazendo as listas
for j in $(v)
do
list=lista_"$i"_"$j".dat
xh_header "$i"_stations_1x1_RF_8s_01"$j"00X.cut.xh -h evnt stat arcs | sort -n -k25 > teste.dat
cat teste.dat | awk '{print $4" "$5" "$6" "$10" "$12" "$13" "$17" "$19" "$25}' | sort -n -k9 > $list
rm teste.dat
for k in $list
do
xh_2sac $PWD/$folder/"$i"_stations_1x1_RF_8s_01"$j"00X.cut.xh -s $k
touch log.dat
echo "r *$k*" > lixo1
echo "chnhdr KT0 'P'" >> lixo1
echo "chnhdr KT1 'Pdiff'" >> lixo1
echo "chnhdr KT2 'S'" >> lixo1
echo "chnhdr KT3 'Sdiff'" >> lixo1
echo "chnhdr KT4 'PcP'" >> lixo1
echo "chnhdr KT5 'PP'" >> lixo1
echo "chnhdr KT6 'SS'" >> lixo1
echo "chnhdr KT7 'P400s'" >> lixo1
echo "chnhdr KT8 'P670s'" >> lixo1
echo "w over" >> lixo1
echo "quit" >> lixo1
sac < lixo1
rm lixo1
done
done
cd $home_folder
mv $home_folder/$folder/lista* $home_folder/Listas/"$i"_lists/
mv $PWD/$folder/*.sac $PWD/sacev/sacev_$i/
#mv $PWD/$folder/log.dat $PWD/sacev/sacev_$i/
mv $PWD/sacev/sacev_$i/ $folder_path
done
the code's name is RFauto and when a do:
bash ./RF
I get the message:
RFauto.sh: row 79: syntax's error next to the unexpected token done' RFauto.sh: row 79: done'
(I had to translate the error massage from portuguese, but I hope it is understandable)
Like I said, he is kinda saying that I already closed the for loop, but when I remove it, it says that I need to close the for loop.
I will be vary grateful for any help!
you need for i in "${models[#]}" to iterate over the elements of the array.
This is correct shell syntax but not what you intend
if ( ! -e $PWD/Listas )
then
mkdir $PWD/Listas
fi
That will attempt to execute the command -e in a subshell and return the exit status negated.
I would expect to see the error "-e: command not found".
You want to use the [[...]] conditional construct
Additionally, mkdir -p will create a directory if it does not exist (including parent directories if they do not exist); if it does exist there is no error
cd $home_folder
mv $home_folder/$folder/lista* $home_folder/Listas/"$i"_lists/
mv $PWD/$folder/*.sac $PWD/sacev/sacev_$i/
#mv $PWD/$folder/log.dat $PWD/sacev/sacev_$i/
mv $PWD/sacev/sacev_$i/ $folder_path
The cd command changed $PWD. Are you sure that's what you want?
In general using $PWD in a program is risky: do you really know the user's location when they invoke the script?
i j k are not very descriptive variable names.
temporary files are usually not necessary.
#!/bin/bash
#modelos que serão usados
models=( 410_5x5_nocrust ) # 660_5x5_nocrust mtz_2x2_nocrust mtz_5x5_nocrust mtz_8x8_nocrust mtz_11x11_nocrust prem_nocrust prem s40rts_nocrust 660_5x5_s40rts_nocrust tx2015_nocrust)
#numero de eventos q temos por modelo
v=(01 02) #03 04 05 06 07 08 09 10 11 12)
#pasta base de onde todos os arquivos e programas estão
home_folder=/home/felipe/sda1_acess/RF_PROCESSING
for i in "${models[#]}"
do
#criando as pastas importantes para o trabalho
mkdir -p "$PWD/Listas/${i}_lists"
mkdir -p "$PWD/sacev/sacev_${i}/"
#setando a pasta onde os arquivos estão
folder="XH_preprocessed_${i}_stations_1x1_RF_8s"
#acessando a pasta
cd "$home_folder/$folder"
#Fazendo as listas
for j in "${v[#]}"
do
list="lista_${i}_${j}.dat"
xh_header "${i}_stations_1x1_RF_8s_01${j}00X.cut.xh" -h evnt stat arcs \
| sort -n -k25 \
| awk '{print $4, $5, $6, $10, $12, $13, $17, $19, $25}' \
| sort -n -k9 \
| while IFS= read -r k
do
xh_2sac "$PWD/$folder/${i}_stations_1x1_RF_8s_01${j}00X.cut.xh" -s "$k"
touch log.dat
sac << END_INPUT
r *$k*
chnhdr KT0 'P'
chnhdr KT1 'Pdiff'
chnhdr KT2 'S'
chnhdr KT3 'Sdiff'
chnhdr KT4 'PcP'
chnhdr KT5 'PP'
chnhdr KT6 'SS'
chnhdr KT7 'P400s'
chnhdr KT8 'P670s'
w over
quit
END_INPUT
done
done
cd "$home_folder"
mv "$home_folder/$folder/lista"* "$home_folder/Listas/${i}_lists/"
mv "$PWD/$folder/"*.sac "$PWD/sacev/sacev_${i}/"
#mv "$PWD/$folder/log.dat" "$PWD/sacev/sacev_${i}/"
mv "$PWD/sacev/sacev_${i}/" "$folder_path"
done

SOLVED: Adding error messages to an array in bash procedure

Here I placed working example, solved thanks to all you and completed with comments:
#!/bin/bash
errors=() #array to store all errors
to="" #a variable
DEST="" #another variable
from="" #and so on
e=$(mv "$from" "$to" 2>&1) #this command makes first error
if [ -n "$e" ] ;then errors+=("$e"); fi #and this save it to array
e=$(mv "$DEST" "$to" 2>&1) #so this makes second error
if [ -n "$e" ] ; then errors+=("$e"); fi #and this saves it to array
if [ ${#errors[#]} -eq 0 ]; then #if no errors
echo OK
else #if there are error (YES)
echo "ATTENZIONE: SI SONO VERIFICATI DEGLI ERRORI DURANTE L'OPERAZIONE DI RESTORE:"
for t in "${errors[#]}"; do #display all errors
echo "$t"
done
fi
Thank you very mutch.
This is the first answare before the solution:
I need to add to an array all error messages in my bash file.
Thanks to shellcheck.net and Cyrus and Freddy I adjusted code:
I did it:
#!/bin/bash
#set -x #DEBUG
errors=()
to=""
DEST=""
if ! mv "$from" "$to" ; then errors+=("$?"); fi
if ! mvv "$DEST" "$to" ; then errors+=("$?"); fi
if [ ${#errors[#]} -eq 0 ]; then
echo OK
else
echo "ATTENZIONE: SI SONO VERIFICATI DEGLI ERRORI DURANTE L'OPERAZIONE DI RESTORE:"
for t in "${errors[#]}"; do
echo "$t"
done
fi
the output that I obtain is :
ATTENZIONE: SI SONO VERIFICATI DEGLI ERRORI DURANTE L'OPERAZIONE DI RESTORE:
0
0
How can I do to obtain the right error messages in my array "$errors" ?
Thanks
The problem is that you aren't getting the exit status of the command (e.g. mv "$from" "$to"), but of the negated command (e.g. ! mv "$from" "$to") -- since the command failed (nonzero exit status), the negated status is success (zero). In order to do this, you need to avoid negating the status between the command and when you record the status. The easiest way I know of to do this is to use || instead of if, like this:
mv "$from" "$to" || errors+=("$?")

file system disk usage script

I have a multiple choice menu script to display top file system disk usage. It is working script but I have problem with one of the file system naming /data.
DATA_RAW_DISK_DUMP="/tmp/$(basename $0).$$.disk_raw_data"
DATA_RAW_FILE_LIST="/tmp/$(basename $0).$$.file_raw_data"
MY_WORKING_DIR=$(pwd)
MY_OUTPUT_FILE="MY_WORKING_DIR/$(basename $0).output"
#check existing output file
if [[ -e $MY_OUTPUT_FILE ]] ; then
if [[ -e ${MY_OUTPUT_FILE}.old ]] ; then
rm ${MY_OUTPUT_FILE}.old
fi
mv $MY_OUTPUT_FILE ${MY_OUTPUT_FILE}.old
fi
#will prompt for choices - ignore any arguments
echo "Please select from below:" cat<<EOF
1. /data
2. /data01
3. DO_ALL_DATA_AT_ONCE
Press ENTER to exit EOF
echo -n "Selection:"
read ans
if [[ $ans == "" ]] ; then
echo "Bye"
exit 0
fi
case $ans in
"1"|"2"|"3")
FS_TARGET="$ans"
;;
*)
echo "Unknown option - quitting"
echo "Bye"
exit 0
;;
esac
DATA="/data0${FS_TARGET}/*"
if [[ $FS_TARGET -eq 3 ]] ; then
#if the selection is 3, then we just do everything, in one go
DATA="/data/* /data01/*"
fi
#do the du first
echo "Running du for ${DATA}, this will take a while, please wait..." >&2
du -sk ${DATA} > $DATA_RAW_DISK_DUMP 2>/dev/null
#we need to check each entry, if its directory, go into it and get the youngest file
echo "Checking file age for ${DATA}, this will take a while, please wait..." >&2
for i in $(cat $DATA_RAW_DISK_DUMP | awk '{print $2}') ; do
if [[ -d $i ]] ; then
#we need to find the youngest file in this directory tree
YOUNGEST_FILE="$(find $i -type f -printf "%C# %p\n" | sort -rn | head -n 1|sed 's,[0-9]*[.][0-9]*[ ],,g')"
if [[ $YOUNGEST_FILE == "${i}" ]] ; then
stat --format "%n;%Y;%X;%U" "$i" >> $DATA_RAW_FILE_LIST 2>/dev/null
elif [[ $YOUNGEST_FILE == "" ]] ; then
stat --format "%n;%Y;%X;%U" "$i" >> $DATA_RAW_FILE_LIST 2>/dev/null
else
stat --format "%n;%Y;%X;%U" "$YOUNGEST_FILE" >> $DATA_RAW_FILE_LIST 2>/dev/null
fi
else
stat --format "%n;%Y;%X;%U" "$i" >> $DATA_RAW_FILE_LIST 2>/dev/null
fi
done
The script above, option 2 & 3 will work fine but option 1 show nothing. Then I try another way by adding another variable into the script and it did not work as well. Can someone show me how to make it read my file system /data?
echo "Please select from below:"
cat<<EOF
1. /data
2. /data01
3. DO_ALL_DATA_AT_ONCE
Press ENTER to exit
EOF
echo -n "Selection:"
read ans
if [[ $ans == "" ]] ; then
echo "Bye"
exit 0
fi
case $ans in
"1"|"2"|"3")
FS_TARGET="$ans"
;;
*)
echo "Unknown option - quitting"
echo "Bye"
exit 0
;;
esac
DATA="/data0${FS_TARGET}/*"
if [[ $FS_TARGET -eq 1 ]] ; then
#if the selection is 1, then change do the variable....
DATA="/data/*"
fi
if [[ $FS_TARGET -eq 3 ]] ; then
#if the selection is 3, then we just do everything, in one go
DATA="/data/* /data01/*"
fi

script bash Linux don't find error

I have to verify in a script bash that a folder exists. The problem is, it does but the script tells me that my file does not exist.
I don't find the error and I have searched on the internet and I do exactly the way it says to do( on Openclassroom, forum, ...).
here is my script:
#!/bin/bash
if [ $# -ne 1 ] && [ -d $1 ]; then
echo "Usage : $0 dir">/dev/stderr
exit 1
fi
backup="~/backup"
echo $backup , argument = $1
if [ ! -e ${backup} ]; then
echo "Le dossier backup n'existe pas">/dev/stderr
exit 1
fi
if [ ! -d $backup ]; then
echo "le document backup n'est pas un fichier">/dev/stderr
exit 1
fi
if [ -w $backup ]; then
echo "Le dossier backup n'est pas protégé en écriture">/dev/stderr
exit 1
fi
il qu$if [! chmod u=+w $backup ]; then
echo "une erreur c'est produite">/dev/stderr
exit 1
fi
And what it said in the shell + the proof that the file backup exist in the correct repertory:
guy#PC-DE-GUY:~/bash/Chap9$ ./backup.sh ~/seance06/
~/backup , argument = /home/guy/seance06/
Le dossier backup n'existe pas
guy#PC-DE-GUY:~/bash/Chap9$ ~/backup
bash: /home/guy/backup : est un dossier
guy#PC-DE-GUY:~/bash/Chap9$ cd ~/backup
guy#PC-DE-GUY:~/backup$
The issue is with the ~ character inside quotes, in backup="~/backup" (line 6). BASH processes it as a character, not as an alias to your home directory, so your code runs the checks on the string '~/backup', instead of '/home/guy/backup'.
To use ~ as an alias to your home directory, it should be outside quotes: backup=~/backup
If you want to hardcode your home directory, I suggest you use $HOME instead of ~. It's clearer to understand.
You can test what I tried to explain with the following code:
#!/bin/bash
# Save this file as test.sh
# run this script with ~ as an argument:
# ./test.sh ~
echo "Value for \$HOME: $HOME"
echo "Value for ~ inside quotes: ~"
echo "Value for ~ outside quotes:" ~
echo "Value for \$1: $1"
If you save the code above as test.sh and you run it as: ./test.sh ~, outputs will be:
Value for $HOME: /home/guy
Value for ~ inside quotes: ~
Value for ~ outside quotes: /home/guy
Value for $1: /home/guy

remove the content of a directory and the directory itself when it become empty

I'm trying to write my own rm command using a bash script, my new command called "remove" accept one or several params (file and folders), and it must act like this:
when it found a file : it must check the parent for permission before deleting it
when it found an empty directory, it have to delete it
and the last case, when it found a non empty folder, it must delete all its content after checking permissions for course, and if the parent directory became empty my command must remove it too
My problem is that the third case doesn't work for me
here is my code
#!/bin/bash
if [ $# -lt 1 ]
then
echo "Executer la commande avec au moins un paramètre"
else
for i in $*
do
filename=`basename $i`
#echo "nom fichier : $filename"
path=`dirname $i`
#echo "chemin du fichier : $path"
#Vérification de l'existence du fichier/rep
if [ -e $path/$filename ]
then
# Si fichier
if [ -f $path/$filename ]
then
echo "fichier"
$HOME/droit_parent $path
valretourne=$?
if [ $valretourne -eq 20 ]
then
echo "Erreur : `dirname $path` n\'a pas le droitW"
else if [ $valretourne -eq 10 ]
then
rm -f $path/$filename
echo "$path/$filename a été bien supprimé"
fi
fi
fi
#Si rep
if [ -d $path/$filename ]
then
echo "repertoire"
if [ "$(ls -A $path/$filename)" ]
then
echo "non empty directory"
$HOME/remove $path/$filename/*
if [ ! "$(ls -A $path/$filename)" ]
then
rmdir $path/$filename
fi
else
echo "empty directory"
rmdir $path/$filename
fi
fi
else echo "ERREUR : $path/$filename n\'existe pas !"
fi
done
fi
In order to find an empty directory I think it would be much easier if you use find instead of listing the files/folder in that dir and based on that decide if that dir is empty or not.
You can use find like this:
find . -type d -empty

Resources