I am trying to build a script/program that runs a sh file on internet without downloading it. All was working fine, with the exception that i am getting "This file/command doesnt exist" error on gedit, apt, etc. Then, I tried to modify the script to download the file and execute it after this instead of running bash <(curl -s --max-redirs 10 $2 -L), but still not working. I realized that if I finalize the script, CD to the downloaded SH file path and run it using "bash + foo.sh", it is still not working. The only method I found to run it is editing the SH file using gedit, copy all the content, remove the SH file, create a new SH file, paste and run it.
What is happening? Why is it not working? I want to run a SH script on the web just with bash without downloading it (bash and curl).
Here is my script (I will send it to my github when I end):
#!/bin/bash
input=$*
mkdir "$HOME/.br" > /dev/null 2>&1
mkdir "$HOME/.br/cache" > /dev/null 2>&1
rm "$HOME/.br/cache/*" > /dev/null 2>&1
if [ "$input" == "" ]
then
echo '[X] ERRO! | ERROR! | ¡ERROR!'
echo
echo '[PT]: Você precisa digitar um argumento. Digite "br -- help" para obter ajuda.'
echo
echo '[EN]: You need to type an argument. Type "br --help" to get help.'
echo
echo '[ES]: Debes ingresar un argumento. Escriba "br --help" para obtener ayuda.'
exit
fi
if [ "$input" == "--ajuda" ] || [ "$input" == "--help" ] || [ "$input" == "-h" ] || [ "$input" == "--ayuda" ] || [ "$input" == "-?" ]
then
echo '[?] AJUDA | HELP | AYUDA'
echo
echo '[PT]: Acesse este link para obter ajuda: '
echo
echo '[EN]: Go to this link for help: '
echo
echo '[ES]: Vaya a este link para obtener ayuda: '
exit
fi
if [ "$1" == "-u" ] || [ "$1" == "--url" ]
then
curl -s --max-redirs 10 $2 -L >$HOME/.br/cache/sh.sh
chmod +x "$HOME/.br/cache/sh.sh"
bash "$HOME/.br/cache/sh.sh" $1 $2 $3 $4 $5 $6 $7 $8 $9
else
curl -s --max-redirs 10 tiny.cc/brl_$1 -L >$HOME/.br/cache/sh.sh
chmod +x "$HOME/.br/cache/sh.sh" $1 $2 $3 $4 $5 $6 $7 $8 $9
fi
Also:
PS: I know that downloading files without reading the content before is unsafe, and because of it I pretend to make a dialog that shows its content, if the user wants it.
PS2: You can see that line: curl -s --max-redirs 10 tiny.cc/brl_$1 -L >$HOME/.br/cache/sh.sh. I am making a functionality that you can just short a link using tiny.cc with "brl_filename" and acess it typing "./script.sh filename" (That acess the SH file stored on 'tiny.cc/brl_filename'). It's like APT-GET, but its a SH script 'reader', and i'm using the tiny.cc as a 'database'. Imagine some website saying: "To install my app, just type foo filename or click in This button (foo://filename), and all twill be done. If you want to view what is inside the file, type foo -v filename or click in This button (foo://v:filename)!" - It's exactly it I'm trying to do, simplify the linux installing for all users, including the noobie users.
This project will be hosted on https://github.com/Felipecconde/br.
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
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
This code is that I want to give two directory and this code will look if these two directory contains two files that contains the same information, and asks me which file I want to delete .
I have written this code but I don't know how to write the code that will delete the file , please help
#!bin/bash
echo "give the first directory"
read firstdir
echo "give the second directory"
read seconddir
for i in ` ls $firstdir`
do
echo $i
t= `md5sum $firstdir/$i`
s= `md5sum $seconddir/$i`
if [ "$t" ! = "$s" ]
then
echo " of which directory will be eliminated? $i"
read direct
( here I want the code to delete the directory ex : delete direct/i )
fi
done
Replace:
echo " of which directory will be eliminated? $i"
read direct
( here I want the code to delete the directory ex : delete direct/i )
With:
echo "of which directory will be eliminated? $i:
1)$firstdir
2)$seconddir
"
read -p "(1/2)" direct
case $direct in
1)
rm -v $firstdir/$i
;;
2)
rm -v $seconddir/$i
;;
*)
echo "ERROR: bad value, 1 or 2 expected!" ; exit 1
esac
Ok, try this. I just made my own solution based on your requirements. I hope you like it. Thanks
#!/bin/bash
# check for a valid first directory
while true
do
echo "Please, enter the first directory"
read FIRST_DIR
if [ -d $FIRST_DIR ]; then
break
else
echo "Invalid directory"
fi
done
# check for a valid second directory
while true
do
echo "Please, give the second directory"
read SECOND_DIR
if [ -d $SECOND_DIR ]; then
break
else
echo "Invalid directory"
fi
done
for FILE in `ls $FIRST_DIR`
do
# make sure that only files will be avaluated
if [ -f $FILE ]; then
echo $SECOND_DIR/$FILE
# check if the file exist in the second directory
if [ -f $SECOND_DIR/$FILE ]; then
# compare the two files
output=`diff -c $FIRST_DIR/$FILE $SECOND_DIR/$FILE`
if [ ! $output ]; then
echo "Which file do you want to delete?
1)$FIRST_DIR/$FILE
2)$SECOND_DIR/$FILE
"
# read a choice
read -p "(1/2)" choice
# delete the chosen file
case $choice in
1)
rm -v $FIRST_DIR/$FILE
;;
2)
rm -v $SECOND_DIR/$FILE
;;
*)
echo "ERROR invalid choice!"
esac
fi
else
echo "There are no equal files in the two directories."
exit 1
fi
else
echo "There are no files to be evaluated."
fi
done
How can I determine the name of the Bash script file inside the script itself?
Like if my script is in file runme.sh, then how would I make it to display "You are running runme.sh" message without hardcoding that?
me=`basename "$0"`
For reading through a symlink1, which is usually not what you want (you usually don't want to confuse the user this way), try:
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
IMO, that'll produce confusing output. "I ran foo.sh, but it's saying I'm running bar.sh!? Must be a bug!" Besides, one of the purposes of having differently-named symlinks is to provide different functionality based on the name it's called as (think gzip and gunzip on some platforms).
1 That is, to resolve symlinks such that when the user executes foo.sh which is actually a symlink to bar.sh, you wish to use the resolved name bar.sh rather than foo.sh.
# ------------- SCRIPT ------------- #
#!/bin/bash
echo
echo "# arguments called with ----> ${#} "
echo "# \$1 ----------------------> $1 "
echo "# \$2 ----------------------> $2 "
echo "# path to me ---------------> ${0} "
echo "# parent path --------------> ${0%/*} "
echo "# my name ------------------> ${0##*/} "
echo
exit
# ------------- CALLED ------------- #
# Notice on the next line, the first argument is called within double,
# and single quotes, since it contains two words
$ /misc/shell_scripts/check_root/show_parms.sh "'hello there'" "'william'"
# ------------- RESULTS ------------- #
# arguments called with ---> 'hello there' 'william'
# $1 ----------------------> 'hello there'
# $2 ----------------------> 'william'
# path to me --------------> /misc/shell_scripts/check_root/show_parms.sh
# parent path -------------> /misc/shell_scripts/check_root
# my name -----------------> show_parms.sh
# ------------- END ------------- #
With bash >= 3 the following works:
$ ./s
0 is: ./s
BASH_SOURCE is: ./s
$ . ./s
0 is: bash
BASH_SOURCE is: ./s
$ cat s
#!/bin/bash
printf '$0 is: %s\n$BASH_SOURCE is: %s\n' "$0" "$BASH_SOURCE"
$BASH_SOURCE gives the correct answer when sourcing the script.
This however includes the path so to get the scripts filename only, use:
$(basename $BASH_SOURCE)
If the script name has spaces in it, a more robust way is to use "$0" or "$(basename "$0")" - or on MacOS: "$(basename \"$0\")". This prevents the name from getting mangled or interpreted in any way. In general, it is good practice to always double-quote variable names in the shell.
If you want it without the path then you would use ${0##*/}
To answer Chris Conway, on Linux (at least) you would do this:
echo $(basename $(readlink -nf $0))
readlink prints out the value of a symbolic link. If it isn't a symbolic link, it prints the file name. -n tells it to not print a newline. -f tells it to follow the link completely (if a symbolic link was a link to another link, it would resolve that one as well).
I've found this line to always work, regardless of whether the file is being sourced or run as a script.
echo "${BASH_SOURCE[${#BASH_SOURCE[#]} - 1]}"
If you want to follow symlinks use readlink on the path you get above, recursively or non-recursively.
The reason the one-liner works is explained by the use of the BASH_SOURCE environment variable and its associate FUNCNAME.
BASH_SOURCE
An array variable whose members are the source filenames where the corresponding shell function names in the FUNCNAME array variable are defined. The shell function ${FUNCNAME[$i]} is defined in the file ${BASH_SOURCE[$i]} and called from ${BASH_SOURCE[$i+1]}.
FUNCNAME
An array variable containing the names of all shell functions currently in the execution call stack. The element with index 0 is the name of any currently-executing shell function. The bottom-most element (the one with the highest index) is "main". This variable exists only when a shell function is executing. Assignments to FUNCNAME have no effect and return an error status. If FUNCNAME is unset, it loses its special properties, even if it is subsequently reset.
This variable can be used with BASH_LINENO and BASH_SOURCE. Each element of FUNCNAME has corresponding elements in BASH_LINENO and BASH_SOURCE to describe the call stack. For instance, ${FUNCNAME[$i]} was called from the file ${BASH_SOURCE[$i+1]} at line number ${BASH_LINENO[$i]}. The caller builtin displays the current call stack using this information.
[Source: Bash manual]
Since some comments asked about the filename without extension, here's an example how to accomplish that:
FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
Enjoy!
These answers are correct for the cases they state but there is a still a problem if you run the script from another script using the 'source' keyword (so that it runs in the same shell). In this case, you get the $0 of the calling script. And in this case, I don't think it is possible to get the name of the script itself.
This is an edge case and should not be taken TOO seriously. If you run the script from another script directly (without 'source'), using $0 will work.
Re: Tanktalus's (accepted) answer above, a slightly cleaner way is to use:
me=$(readlink --canonicalize --no-newline $0)
If your script has been sourced from another bash script, you can use:
me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
I agree that it would be confusing to dereference symlinks if your objective is to provide feedback to the user, but there are occasions when you do need to get the canonical name to a script or other file, and this is the best way, imo.
this="$(dirname "$(realpath "$BASH_SOURCE")")"
This resolves symbolic links (realpath does that), handles spaces (double quotes do this), and will find the current script name even when sourced (. ./myscript) or called by other scripts ($BASH_SOURCE handles that). After all that, it is good to save this in a environment variable for re-use or for easy copy elsewhere (this=)...
You can use $0 to determine your script name (with full path) - to get the script name only you can trim that variable with
basename $0
if your invoke shell script like
/home/mike/runme.sh
$0 is full name
/home/mike/runme.sh
basename $0 will get the base file name
runme.sh
and you need to put this basic name into a variable like
filename=$(basename $0)
and add your additional text
echo "You are running $filename"
so your scripts like
/home/mike/runme.sh
#!/bin/bash
filename=$(basename $0)
echo "You are running $filename"
This works fine with ./self.sh, ~/self.sh, source self.sh, source ~/self.sh:
#!/usr/bin/env bash
self=$(readlink -f "${BASH_SOURCE[0]}")
basename=$(basename "$self")
echo "$self"
echo "$basename"
Credits: I combined multiple answers to get this one.
echo "$(basename "`test -L ${BASH_SOURCE[0]} \
&& readlink ${BASH_SOURCE[0]} \
|| echo ${BASH_SOURCE[0]}`")"
In bash you can get the script file name using $0. Generally $1, $2 etc are to access CLI arguments. Similarly $0 is to access the name which triggers the script(script file name).
#!/bin/bash
echo "You are running $0"
...
...
If you invoke the script with path like /path/to/script.sh then $0 also will give the filename with path. In that case need to use $(basename $0) to get only script file name.
Short, clear and simple, in my_script.sh
#!/bin/bash
running_file_name=$(basename "$0")
echo "You are running '$running_file_name' file."
Out put:
./my_script.sh
You are running 'my_script.sh' file.
Info thanks to Bill Hernandez. I added some preferences I'm adopting.
#!/bin/bash
function Usage(){
echo " Usage: show_parameters [ arg1 ][ arg2 ]"
}
[[ ${#2} -eq 0 ]] && Usage || {
echo
echo "# arguments called with ----> ${#} "
echo "# \$1 -----------------------> $1 "
echo "# \$2 -----------------------> $2 "
echo "# path to me ---------------> ${0} " | sed "s/$USER/\$USER/g"
echo "# parent path --------------> ${0%/*} " | sed "s/$USER/\$USER/g"
echo "# my name ------------------> ${0##*/} "
echo
}
Cheers
DIRECTORY=$(cd `dirname $0` && pwd)
I got the above from another Stack Overflow question, Can a Bash script tell what directory it's stored in?, but I think it's useful for this topic as well.
Here is what I came up with, inspired by Dimitre Radoulov's answer (which I upvoted, by the way).
script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"
echo "Called $script with $# argument(s)"
regardless of the way you call your script
. path/to/script.sh
or
./path/to/script.sh
$0 will give the name of the script you are running. Create a script file and add following code
#!/bin/bash
echo "Name of the file is $0"
then run from terminal like this
./file_name.sh
To get the "realpath" of script or sourced scripts in all cases :
fullname=$(readlink $0) # Take care of symbolic links
dirname=${fullname%/*} # Get (most of the time) the dirname
realpath=$(dirname $BASH_SOURCE) # TO handle sourced scripts
[ "$realpath" = '.' ] && realpath=${dirname:-.}
Here is the bash script to generate (in a newly created "workdir" subdir and in "mytest" in current dir), a bash script which in turn will source another script, which in turm will call a bash defined function .... tested with many ways to launch them :
#!/bin/bash
##############################################################
ret=0
fullname=$(readlink $0) # Take care of symbolic links
dirname=${fullname%/*} # Get (most of the time) the dirname
realpath=$(dirname $BASH_SOURCE) # TO handle sourced scripts
[ "$realpath" = '.' ] && realpath=${dirname:-.}
fullname_withoutextension=${fullname%.*}
mkdir -p workdir
cat <<'EOD' > workdir/_script_.sh
#!/bin/bash
##############################################################
ret=0
fullname=$(readlink $0) # Take care of symbolic links
dirname=${fullname%/*} # Get (most of the time) the dirname
realpath=$(dirname $BASH_SOURCE) # TO handle sourced scripts
[ "$realpath" = '.' ] && realpath=${dirname:-.}
fullname_withoutextension=${fullname%.*}
echo
echo "# ------------- RESULTS ------------- #"
echo "# path to me (\$0)-----------> ${0} "
echo "# arguments called with ----> ${#} "
echo "# \$1 -----------------------> $1 "
echo "# \$2 -----------------------> $2 "
echo "# path to me (\$fullname)----> ${fullname} "
echo "# parent path(\${0%/*})------> ${0%/*} "
echo "# parent path(\$dirname)-----> ${dirname} "
echo "# my name ----\${0##*/}------> ${0##*/} "
echo "# my source -\${BASH_SOURCE}-> ${BASH_SOURCE} "
echo "# parent path(from BASH_SOURCE) -> $(dirname $BASH_SOURCE)"
echo "# my function name -\${FUNCNAME[0]}------> ${FUNCNAME[0]}"
echo "# my source or script real path (realpath)------------------> $realpath"
echo
[ "$realpath" = "workdir" ] || ret=1
[ $ret = 0 ] || echo "*******************************************************"
[ $ret = 0 ] || echo "*********** ERROR **********************************"
[ $ret = 0 ] || echo "*******************************************************"
show_params () {
echo
echo "# --- RESULTS FROM show_params() ---- #"
echo "# path to me (\$0)-----------> ${0} "
echo "# arguments called with ----> ${#} "
echo "# \$1 -----------------------> $1 "
echo "# \$2 -----------------------> $2 "
echo "# path to me (\$fullname)----> ${fullname} "
echo "# parent path(\${0%/*})------> ${0%/*} "
echo "# parent path(\$dirname)-----> ${dirname} "
echo "# my name ----\${0##*/}------> ${0##*/} "
echo "# my source -\${BASH_SOURCE}-> ${BASH_SOURCE} "
echo "# parent path(from BASH_SOURCE) -> $(dirname $BASH_SOURCE)"
echo "# my function name -\${FUNCNAME[0]}------> ${FUNCNAME[0]}"
echo "# my source or script real path (realpath)------------------> $realpath"
echo
[ "$realpath" = "workdir" ] || ret=1
[ $ret = 0 ] || echo "*******************************************************"
[ $ret = 0 ] || echo "*********** ERROR **********************************"
[ $ret = 0 ] || echo "*******************************************************"
}
show_params "$#"
EOD
cat workdir/_script_.sh > workdir/_side_by_side_script_sourced.inc
cat <<'EOD' >> workdir/_script_.sh
echo "# . $realpath/_side_by_side_script_sourced.inc 'hello there' 'william'"
. $realpath/_side_by_side_script_sourced.inc 'hello there' 'william'
[ $ret = 0 ] || echo "*******************************************************"
[ $ret = 0 ] || echo "*********** ERROR **********************************"
[ $ret = 0 ] || echo "*******************************************************"
EOD
chmod +x workdir/_script_.sh
[ -L _mytest_ ] && rm _mytest_
ln -s workdir/_script_.sh _mytest_
# ------------- CALLED ------------- #
called_by () {
echo '=========================================================================='
echo " Called by : " "$#"
echo '=========================================================================='
eval "$#"
}
called_by bash _mytest_
called_by ./_mytest_
called_by bash workdir/_script_.sh
called_by workdir/_script_.sh
called_by . workdir/_script_.sh
# ------------- RESULTS ------------- #
echo
echo
[ $ret = 0 ] || echo "*******************************************************"
[ $ret = 0 ] || echo "*********** ERROR **********************************"
[ $ret = 0 ] || echo "*******************************************************"
echo
[ $ret = 0 ] && echo ".... location of scripts (\$realpath) should always be equal to $realpath, for all test cases at date".
echo
# ------------- END ------------- #
echo "You are running $0"
somthing like this?
export LC_ALL=en_US.UTF-8
#!/bin/bash
#!/bin/sh
#----------------------------------------------------------------------
start_trash(){
ver="htrash.sh v0.0.4"
$TRASH_DIR # url to trash $MY_USER
$TRASH_SIZE # Show Trash Folder Size
echo "Would you like to empty Trash [y/n]?"
read ans
if [ $ans = y -o $ans = Y -o $ans = yes -o $ans = Yes -o $ans = YES ]
then
echo "'yes'"
cd $TRASH_DIR && $EMPTY_TRASH
fi
if [ $ans = n -o $ans = N -o $ans = no -o $ans = No -o $ans = NO ]
then
echo "'no'"
fi
return $TRUE
}
#-----------------------------------------------------------------------
start_help(){
echo "HELP COMMANDS-----------------------------"
echo "htest www open a homepage "
echo "htest trash empty trash "
return $TRUE
} #end Help
#-----------------------------------------------#
homepage=""
return $TRUE
} #end cpdebtemp
# -Case start
# if no command line arg given
# set val to Unknown
if [ -z $1 ]
then
val="*** Unknown ***"
elif [ -n $1 ]
then
# otherwise make first arg as val
val=$1
fi
# use case statement to make decision for rental
case $val in
"trash") start_trash ;;
"help") start_help ;;
"www") firefox $homepage ;;
*) echo "Sorry, I can not get a $val for you!";;
esac
# Case stop