When shell scripts echos "*", why it lists the files and directories? - linux

I have written the following shell script to print "*" on the screen but when I execute the script, it lists all the files and directories in the current directory in which script is located. Can someone tell me why the script lists all the files and directories in the current directory?
#!/bin/bash
TEST="*";
echo $TEST

Because there are missing some "" around the $TEST.
Try echo "$TEST".

It prints all the files and folders because the shell, bash in your case, expands the * before passing it to the command.
The solution is simple:
#!/bin/bash
TEST="*";
echo "$TEST"

Related

How do I execute .AppImage files using regular expressions in bash scripts?

I want to execute a .AppImage program using regular expressions because the .AppImage updates it's name every time I update it.
My code:
#!/bin/bash
./home/myname/Applications/myApplication-*.AppImage
Output:
./launch_myApplication.sh: line 3: ./home/myname/Applications/myApplication-*.AppImage: No such file or directory
The real .AppImage name is "myApplication-2-11-2.AppImage", but as written above: the verison number changes every update.
How do I execute .AppImage files using regular expressions in bash scripts?
run in relative path
cd YOUR-TARGET-DIRECTORY
# save the name in cmd
cmd=$(echo myApplication-*.AppImage)
# run it
./$cmd
run in absolute path
cmd=$(echo /home/myname/Applications/myApplication-*.AppImage)
# WRONG
#./$cmd
# CORRECT
$cmd
safer
#!/bin/bash
filename='/home/myname/Applications/myApplication-*.AppImage';
if [[ -f "$filename" ]]; then
$filename;
else
echo "$filename not found";
fi
NOTE
if your $HOME is /home/myname you need to update your script
#!/bin/bash
# wrong
# ./home/myname/Applications/myApplication-*.AppImage
# right
/home/myname/Applications/myApplication-*.AppImage

How do I search for bash script files without having a specific extension within a folder?

I want to find bash script files under folders in Array.
But bash script files do not have a specified extension.
I wrote something like this:
for i in "${array[#]}"
do
# Here I will write the condition that the file is found in the folder $k
done
If your scripts have #!/bin/bash or #!/bin/sh in their first line (as they should), then you can use the file command to check if a file is a script or not.
For example, take this script:
#!/bin/bash
echo "I am a script!"
Output of file filename.sh will be filename.sh: Bourne-Again shell script, ASCII text executable, which is indicating it is a shell script. Note that the file command does not use the extension of the file to indicate its format, but uses the content of it.
If you don't have those lines at the beginning of your file, You can try to run every file (command: bash filename.ext) and the check if it was run successfully or not by checking the value of the variable ${?}. This is not a clean method but it sure can help if you have no other choices.
The file command determines a file type.
e.g
#!/bin/bash
arr=(~/*)
for i in "${arr[#]}"
do
type=`file -b $i | awk '{print $2}'`
if [[ $type = shell ]];then
echo $i is a shell script
fi
done

Script cannot find file

I am trying to run a script named myscript.command on a Mac/Linux machine.
#!/bin/sh
echo 'Starting'
chmod 777 ./myfile
The problem is that when I get to the chmod part I get this output:
chmod ./myfile: No such file or directory
But both myscript.command and the myfile are in the same folder.
EDIT
It seems that when I launch the script the script's location is not being preserved. How can I preserve the location?
The script is being launched via double click in the UI.
$0
In order to change the current working directory to the script's directory, put the following command right after the shebang line:
cd "$(dirname "$0")"
The $0 variable expands to the script name (path to the script), and dirname returns path to the script's directory.
Detecting the current working directory
You can use pwd command to get the current working directory. If you are actually running Bash (I'm not sure, since the shebang in your code points to /bin/sh), you can use the built-in $PWD variable:
PWD
The current working directory as set by the cd builtin.
Storing the script's path into variable
Alternatively, save the directory path into a variable, and use it in the script, e.g.:
dir="$(cd $(dirname "$0"); pwd)"
chmod 770 "$dir/somefile"
Double quotes
Note the use of double quotes. Double quotes prevent reinterpretation of special characters. It is also the way to pass strings containing spaces as a single word:
dir="some directory name"
cd "$dir"
Without double quotes the words are interpreted as separate arguments.
You might start off something like this, too..
#!/bin/sh
echo 'Starting'
if [ -f ./myfile ]; then
chmod 777 ./myfile
else
echo "File does not exist:"
ls -l
fi

Bash script that will execute a program over all files in a directory

Writing a bash script that will execute the program 'main' over all the files in the directory 'allfiles'. Main is an executable. The results are then directed to the file 'output.dat'.
Whenever I run the bash script I get the error "./main: no such file or directory". The bash script, main, and 'allfiles' directory are all in the '/home/directory/'. I'm not certain as to why i'm getting this error, or if i'm writing the bash script correctly. Any help is greatly appreciated.
#!/bin/bash
for file in /home/directory/allfiles/*
do
./main $file >> output.dat
done
edit: should clarify that 'main' is an executable file produced from a makefile
If you're not in /home/directory when you run the script, then it won't be able to find main. Try
#!/bin/bash
for file in /home/directory/allfiles/*
do
/home/directory/main $file >> output.dat
done
Additionally, if main is not executable, you'll have to get bash to call it manually. Use bash /home/directory/main $file for that, or make main executable using chmod +x main.
I prefer using find in this case of use. You can manage using subdirs ;)
#!/bin/bash
main=./main
basedir=/home/directory/allfiles/
outFile=output.dat
for file in $(find $basedir -type f)
do
$main $file >> $outFile
done

Equivalent of %~dp0 (retrieving source file name) in sh

I'm converting some Windows batch files to Unix scripts using sh. I have problems because some behavior is dependent on the %~dp0 macro available in batch files.
Is there any sh equivalent to this? Any way to obtain the directory where the executing script lives?
The problem (for you) with $0 is that it is set to whatever command line was use to invoke the script, not the location of the script itself. This can make it difficult to get the full path of the directory containing the script which is what you get from %~dp0 in a Windows batch file.
For example, consider the following script, dollar.sh:
#!/bin/bash
echo $0
If you'd run it you'll get the following output:
# ./dollar.sh
./dollar.sh
# /tmp/dollar.sh
/tmp/dollar.sh
So to get the fully qualified directory name of a script I do the following:
cd `dirname $0`
SCRIPTDIR=`pwd`
cd -
This works as follows:
cd to the directory of the script, using either the relative or absolute path from the command line.
Gets the absolute path of this directory and stores it in SCRIPTDIR.
Goes back to the previous working directory using "cd -".
Yes, you can! It's in the arguments. :)
look at
${0}
combining that with
{$var%Pattern}
Remove from $var the shortest part of $Pattern that matches the back end of $var.
what you want is just
${0%/*}
I recommend the Advanced Bash Scripting Guide
(that is also where the above information is from).
Especiall the part on Converting DOS Batch Files to Shell Scripts
might be useful for you. :)
If I have misunderstood you, you may have to combine that with the output of "pwd". Since it only contains the path the script was called with!
Try the following script:
#!/bin/bash
called_path=${0%/*}
stripped=${called_path#[^/]*}
real_path=`pwd`$stripped
echo "called path: $called_path"
echo "stripped: $stripped"
echo "pwd: `pwd`"
echo "real path: $real_path
This needs some work though.
I recommend using Dave Webb's approach unless that is impossible.
In bash under linux you can get the full path to the command with:
readlink /proc/$$/fd/255
and to get the directory:
dir=$(dirname $(readlink /proc/$$/fd/255))
It's ugly, but I have yet to find another way.
I was trying to find the path for a script that was being sourced from another script. And that was my problem, when sourcing the text just gets copied into the calling script, so $0 always returns information about the calling script.
I found a workaround, that only works in bash, $BASH_SOURCE always has the info about the script in which it is referred to. Even if the script is sourced it is correctly resolved to the original (sourced) script.
The correct answer is this one:
How do I determine the location of my script? I want to read some config files from the same place.
It is important to realize that in the general case, this problem has no solution. Any approach you might have heard of, and any approach that will be detailed below, has flaws and will only work in specific cases. First and foremost, try to avoid the problem entirely by not depending on the location of your script!
Before we dive into solutions, let's clear up some misunderstandings. It is important to understand that:
Your script does not actually have a location! Wherever the bytes end up coming from, there is no "one canonical path" for it. Never.
$0 is NOT the answer to your problem. If you think it is, you can either stop reading and write more bugs, or you can accept this and read on.
...
Try this:
${0%/*}
This should work for bash shell:
dir=$(dirname $(readlink -m $BASH_SOURCE))
Test script:
#!/bin/bash
echo $(dirname $(readlink -m $BASH_SOURCE))
Run test:
$ ./somedir/test.sh
/tmp/somedir
$ source ./somedir/test.sh
/tmp/somedir
$ bash ./somedir/test.sh
/tmp/somedir
$ . ./somedir/test.sh
/tmp/somedir
This is a script can get the shell file real path when executed or sourced.
Tested in bash, zsh, ksh, dash.
BTW: you shall clean the verbose code by yourself.
#!/usr/bin/env bash
echo "---------------- GET SELF PATH ----------------"
echo "NOW \$(pwd) >>> $(pwd)"
ORIGINAL_PWD_GETSELFPATHVAR=$(pwd)
echo "NOW \$0 >>> $0"
echo "NOW \$_ >>> $_"
echo "NOW \${0##*/} >>> ${0##*/}"
if test -n "$BASH"; then
echo "RUNNING IN BASH..."
SH_FILE_RUN_PATH_GETSELFPATHVAR=${BASH_SOURCE[0]}
elif test -n "$ZSH_NAME"; then
echo "RUNNING IN ZSH..."
SH_FILE_RUN_PATH_GETSELFPATHVAR=${(%):-%x}
elif test -n "$KSH_VERSION"; then
echo "RUNNING IN KSH..."
SH_FILE_RUN_PATH_GETSELFPATHVAR=${.sh.file}
else
echo "RUNNING IN DASH OR OTHERS ELSE..."
SH_FILE_RUN_PATH_GETSELFPATHVAR=$(lsof -p $$ -Fn0 | tr -d '\0' | grep "${0##*/}" | tail -1 | sed 's/^[^\/]*//g')
fi
echo "EXECUTING FILE PATH: $SH_FILE_RUN_PATH_GETSELFPATHVAR"
cd "$(dirname "$SH_FILE_RUN_PATH_GETSELFPATHVAR")" || return 1
SH_FILE_RUN_BASENAME_GETSELFPATHVAR=$(basename "$SH_FILE_RUN_PATH_GETSELFPATHVAR")
# Iterate down a (possible) chain of symlinks as lsof of macOS doesn't have -f option.
while [ -L "$SH_FILE_RUN_BASENAME_GETSELFPATHVAR" ]; do
SH_FILE_REAL_PATH_GETSELFPATHVAR=$(readlink "$SH_FILE_RUN_BASENAME_GETSELFPATHVAR")
cd "$(dirname "$SH_FILE_REAL_PATH_GETSELFPATHVAR")" || return 1
SH_FILE_RUN_BASENAME_GETSELFPATHVAR=$(basename "$SH_FILE_REAL_PATH_GETSELFPATHVAR")
done
# Compute the canonicalized name by finding the physical path
# for the directory we're in and appending the target file.
SH_SELF_PATH_DIR_RESULT=$(pwd -P)
SH_FILE_REAL_PATH_GETSELFPATHVAR=$SH_SELF_PATH_DIR_RESULT/$SH_FILE_RUN_BASENAME_GETSELFPATHVAR
echo "EXECUTING REAL PATH: $SH_FILE_REAL_PATH_GETSELFPATHVAR"
echo "EXECUTING FILE DIR: $SH_SELF_PATH_DIR_RESULT"
cd "$ORIGINAL_PWD_GETSELFPATHVAR" || return 1
unset ORIGINAL_PWD_GETSELFPATHVAR
unset SH_FILE_RUN_PATH_GETSELFPATHVAR
unset SH_FILE_RUN_BASENAME_GETSELFPATHVAR
unset SH_FILE_REAL_PATH_GETSELFPATHVAR
echo "---------------- GET SELF PATH ----------------"
# USE $SH_SELF_PATH_DIR_RESULT BEBLOW
I have tried $0 before, namely:
dirname $0
and it just returns "." even when the script is being sourced by another script:
. ../somedir/somescript.sh

Resources