shell script to find file name from its path - shell

Hello i want a simple shell script that find the name of the file from a given path of the file. like
$path = "/var/www/html/test.php";
then i want to get value "test" in some variable. Also only .php files are present.I am using bash shell.
Thanks

Try:
path="/var/www/html/test.php"
name=$(basename "$path" ".php")
echo "$name"
The quotes are only there to prevent problems when $path contains spaces.

Use the built in UNIX command:
basename "/var/www/html/test.php"

Use the basename() function. It is buily in UNIX function

string="/var/www/html/test.php"
oIFS="$IFS"; IFS='/'
set -A str $string
IFS="$oIFS"
echo "strings count = ${#str[#]}"
len=${#str[#]}
pos=`expr $len - 1`
echo "file : ${str[$pos]}";
Output-
strings count = 4
file : test.php

Related

How can I get the first extension of a filename in a shell script?

Is there an inline command which can be used to get the first extension of a file ?
I use the following command to get the latest:
FILE="filename.tar.bz2"
EXT="${FILE##*.}"
echo "EXT = ${EXT}"
which returns
EXT = bz2
Is there a similar command to isolate "tar" only ?
var="config/filename.tar.bz2"
ext=$(basename "$var") # extract filename only
ext=${ext#*.} # remove everything in front the first dot
ext=${ext%%.*} # remove everything after a dot
echo "$ext"
Note: uppercase variables by convention are used for exported variables like COLUMNS, LINES UID PWD TERM etc. Prefer using lowercase variables in your scripts.
Expanding on good answer from #KamilCuk, using only POSIX shell grammar and no external command sub-shell call:
#!/usr/bin/env sh
filepath="/path/to/config/filename.tar.bz2.bak"
echo 'filepath:' "$filepath"
# remove everything upto and including last /
filename="${filepath##*/}"
echo 'filename:' "$filename"
# remove everything until and including first dot
all_extensions="${filename#*.}"
echo 'all_extensions:' "$all_extensions"
# remove everything from and including first dot
first_extension="${all_extensions%%.*}"
echo 'First extension:' "$first_extension"
last_extension="${all_extensions##*.}"
echo 'Last extension:' "$last_extension"
# Fill argument array with extensions
IFS='.'; set -- $all_extensions
if [ $# -gt 0 ]
then
ext_num=1
printf '\nIterating all %d extensions:\n' $#
printf '%s\t%s\n' 'ext#' 'extension'
for extension
do
printf '%4d\t%s\n' "$ext_num" "$extension"
ext_num="$((ext_num+1))"
done
fi
Output:
filepath: /path/to/config/filename.tar.bz2.bak
filename: filename.tar.bz2.bak
all_extensions: tar.bz2.bak
First extension: tar
Last extension: bak
Iterating all 3 extensions:
ext# extension
1 tar
2 bz2
3 bak
$ filename="filename.tar.bz2"
$ echo ${filename##*.}
ext
$ file_ext=${filename##*.} #put to variable
$ echo ${file_ext}
ext
echo "filename.tar.gz" | awk -F "." '{print $2}'
This outputs the first instance of a string between periods. In this case, 'tar'.

Parse ${} placeholder into absolute path in shell script

I have a app.properties file something like below
Base.dir="/user/test/application"
Result.dir="${base.dir}/result"
and i've create bash script to parse above properties
function readConfigFile()
{
(grep -E "^${2}=" -m 1 "${1}" 2>/dev/null || echo "VAR=__UNDEFINED__") | head -n 1 | cut -d '=' -f 2-;
}
function setConfigFile()
{
sourceFile=${1}
}
function configGet()
{
if [ ! -z $sourceFile ]; then
val="$(readConfigFile $sourceFile "${1}")";
if [ "${val}" = "__UNDEFINED__" ]; then
echo "${1} value not exist"
# return empty string
printf -- "%s" "";
fi
printf -- "%s" "${val}";
else
echo "config file not exist"
# return empty string
printf -- "%s" "";
fi
}
and the way i call above parser is something like below
$Result_dir=$(configGet Result.dir)
however, i cant really translate placeholder ${} into base_dir
and i got following error
ls $Result_dir
ls: cannot access ${Base_dir}/result: No such file or directory
Is there any way that i can translate ${Base.dir} into /user/test/application?
I guess you're not going to be able to substitute ${base.dir} (btw shouldn't it be ${Base.dir}?) the way you were hoping mainly because, as far as I know, dots are not allowed in variable names in bash.
What you could do is manually substitute the ${base.dir} part with the corresponding path using bash's substitution syntax. For example:
setConfigFile 'app.properties'
Result_dir_raw=$(configGet Result.dir)
Result_dir=${Result_dir_raw/'${base.dir}'/$(configGet Base.dir)}
echo ${Result_dir}
I say "manually" because you still specify in your source code that the pattern you want to replace is ${base.dir} which I'm guessing isn't what you wanted.
Now if you run this you'll see that the ${Result_dir} variable evaluates to ""/user/test/application"/result" which obviously isn't a path, and this is because you're surrounding the paths in app.properties with double quotes, so you either need to get rid of them in your readConfigFile function or lose them altogether in your config file, which to me makes more sense.
Why have you a . in your variable name, which is not allowed in bash:
$ Base.dir="/user/test/application"
-bash: Base.dir=/user/test/application: No such file or directory
$ Base_dir="/user/test/application"
$
So, why do you get No such file or directory? Here is an explanation:
Create a file called Base.dir=gash.sh, yes, that's a legal filename
$ echo 'echo Hello World' > Base.dir=gash.sh
Make the file executable:
$ PATH=$PATH:.
$ chmod u+x Base.dir=gash.sh
Now type the command:
$ Base.dir="gash.sh"
Hello World
Use an underscore, not a dot. By the Way, ksh Korn shell not only allows the dot, it has a special meaning, it is a compound variable.

ls $FOLDER_PATH with space in $FOLDER_PATH: No such file or directory

I am trying to get the filename in a folder with only one file in it.
FYI: The $FOLDER_TMP contains a space in it, that is why I use printf
function nameofkeyfile(){
FOLDER_TMP="${PWD%/*/*}/folder/"
FOLDER=$(printf %q "${FOLDER_TMP}")
FILENAME=ls "$FOLDER" # Error: No such file or directory
# or this: FILENAME=$(ls "$FOLDER") # Error: No such file or directory
FNAME=`basename $FILENAME`
}
The problem is the line:
FILENAME=ls "$FOLDER" # Error: No such file or directory
Do you know why - and yes the folder is there?
And if I echo the $FOLDER it gives me the right folder.
I am trying to get the filename in a folder with only one file in it.
You definitely have the wrong approach.
Instead, consider using globbing like so:
The assignment
fname=( "${PWD%/*/*}"/folder/* )
will populate the array fname will the expansion of the given glob: that is, all files in the directory "${PWD%/*/*}"/folder/, if any. If there are no files at all, your array will contain the glob, verbatim.
Hence, a more robust approach is the following:
nameofkeyfile() {
fname=( "${PWD%/*/*}"/folder/* )
# Now check that there's at most one element in the array
if (( ${#fname[#]} > 1 )); then
echo "Oh no, there are too many files in your folder"
return 1
fi
# Now check that there is a file
if [[ ! -f ${fname[0]} ]]; then
echo "Oh no, there are no files in your folder"
return 1
fi
# Here, all is good!
echo "Your file is: $fname"
}
This uses Bash (named) arrays. If you want the function to be POSIX-compliant, it's rather straightforward since POSIX shells have an unnamed array (the positional parameters):
# POSIX-compliant version
nameofkeyfile() {
set -- "${PWD%/*/*}"/folder/*
# Now check that there's at most one element in the array
if [ "$#" -gt 1 ]; then
echo "Oh no, there are too many files in your folder"
return 1
fi
# Now check that there is a file
if [ ! -f "$1" ]; then
echo "Oh no, there are no files in your folder"
return 1
fi
# Here, all is good!
echo "Your file is: $1, I'll store it in variable fname for you"
fname=$1
}
I didn't strip the full path from the filename, but that's really easy (don't use basename for that!):1
fname=${fname##*/}
More precisely: in the Bash version, you'd use:
fname=${fname[0]##*/}
and in the POSIX version you'd use:
fname=${1##*/}
1there's a catch when using parameter expansions to get the basename, it's the case of /. But it seems you won't be in this case, so it's all safe!
To store the output ls "$FOLDER" in a variable, put it in a sub-shell:
FILENAME=$(ls "$FOLDER")
Another problem is the printf.
It adds escaping backslashes in the string,
and when you try to list the directory in the next step,
those backslashes are used literally by the shell.
So drop the printf:
function nameofkeyfile() {
FOLDER="${PWD%/*/*}/folder/"
FILENAME=$(ls "$FOLDER")
FNAME=$(basename $FILENAME)
}
Lastly, it's better to use $(...) than `...`:

Shell Script: Concatenate string while interating

I am writing a shell script that iterates over directory content and searches for pdf files and creates a string listing all pdf files in it e.g. "pdffile1.pdf pdffile2.pdf pdffile3.pdf".
pdffiles=""
#get files in pdf directory
for filename in $1/*; do
fn=$(basename "$filename")
#check if file exist
if [ -f "$filename" ]; then
#grab only pdf files
if [ ${filename: -4} == ".pdf" ]; then
pdffiles = $filename $pdffiles
fi
fi
done
The thing is this code pdffiles = $filename $pdffiles is wrong and shell script outputs following error message ./mergepdfs.sh: line 39: pdffiles: command not found.
What is wrong with that line?
Don't use spaces around '=' when assigning:
x = 1 # execution of x with arguments '=' and '1'
x=1 # setting shell variable x
Why not simply:
pdffiles=$1/*.pdf
If you like to get them in array form:
pdffiles=($1/*.pdf)
Output all:
echo ${pdffiles[*]}
Output size:
echo ${#pdffiles[*]}
Output a single name:
echo ${pdffiles[4]}
I think you don't need space around =. This must be a correct line:
pdffiles=$filename' '$pdffiles

Bash - if and for statements

I am little unfamiliar with the 'if...then...fi' and the 'for' statements syntax.
Could anyone explain what the "$2/$fn" and "/etc/*release" in the code snippets below mean?...specifically on the use of the forward slash....and the asterisk...
if [ -f "$filename" ]; then
if [ ! -f "$2/$fn" ]; then
echo "$fn is missing from $2"
missing=$((missing + 1))
fi
fi
and
function system_info
{
if ls /etc/*release 1>/dev/null 2>&1; then
echo "<h2>System release info</h2>"
echo "<pre>"
for i in /etc/*release; do
# Since we can't be sure of the
# length of the file, only
# display the first line.
head -n 1 $i
done
uname -orp
echo "</pre>"
fi
} # end of system_info
...thx for the help...
/etc/*release : here the * will match any number of any characters, so any thing /etc/0release , /etc/asdfasdfr_release etc will be matched. Simply stated, it defined all the files in the /etc/ directory which ends with the string release.
The $2 is the 2nd commandline argument to the shell script, and $fn is some other shell variable. The "$2/$fn" after the variable substitutions will make a string, and the [ -f "$2/$fn" ] will test if the string formed after the substitution forms a path to a regular file which is specified by the -f switch. If it is a regular file then the body of if is executed.
In the for loop the loop will loop for all the files ending with the string release in the directory /etc (the path). At each iteration i will contain the next such file name, and for each iteration the first 1 line of the file is displayed with the head command by getting the file name from variable i within the body.
It is better to check the manual man bash and for if condition check man test . Here is a good resource: http://tldp.org/LDP/Bash-Beginners-Guide/html/
The forward slash is the path separator, and the * is a file glob character. $2/$fn is a path where $2 specifies the directory and $fn is the filename. /etc/*release expands to the space separated list of all the files in /etc whose name ends in "release"
Dollar sign marks variable. The "-f" operator means "file exsists".
So,
[ -f "$filename" ]
checks if there is file named the same as value contained in $filename variable.
Simmilar, if we assume that $2 = "some_folder", and $fn = "some_file", expression
[ ! -f "$2/$fn" ]
returns true if file some_folder/some_file doesn't exsist.
Now, about asterisk - it marks "zero or more of any character(s)". So, expression:
for i in /etc/*release; do
will iterate trough all folders named by that pattern, for example:
/etc/release, /etc/666release, /etc/wtf_release...
I hope this helps.

Resources