[SOLVED] bash script - return full path and filename
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
How about this one to get absolute path? Simpler, even local variables are not needed. Little modification will get you the file base name if needed, as soon as you can define its behaviour when you give directory as argument (should it be the last directory or empty string?).
Code:
function abspath {
if [[ -d "$1" ]]
then
pushd "$1" >/dev/null
pwd
popd >/dev/null
elif [[ -e $1 ]]
then
pushd $(dirname $1) >/dev/null
echo $(pwd)/$(basename $1)
popd >/dev/null
else
echo $1 does not exist! >&2
return 127
fi
}
function getabspath {
local -a T1 T2
local -i I=0
local IFS=/ A
case "$1" in
/*)
read -r -a T1 <<< "$1"
;;
*)
read -r -a T1 <<< "/$PWD/$1"
;;
esac
T2=()
for A in "${T1[@]}"; do
case "$A" in
..)
[[ I -ne 0 ]] && unset T2\[--I\]
continue
;;
.|'')
continue
;;
esac
T2[I++]=$A
done
case "$1" in
*/)
[[ I -ne 0 ]] && __="/${T2[*]}/" || __=/
;;
*)
[[ I -ne 0 ]] && __="/${T2[*]}" || __=/.
;;
esac
}
Calling a binary from a bash script can sometimes be preferred. Here's some C code which can be compiled using gcc -Wall -o getpath getpath.c
Code:
// getpath.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Getpath takes one filename or directory as a parameter\n");
exit (1);
}
char AbsPath[strlen(argv[1] + 1)];
realpath(argv[1],AbsPath);
printf("%s\n",AbsPath);
return 0;
}
So if desired, copy the code above to a plain text file called getpath.c and compile it. Then use "./getpath <filename>" If you put getpath is in your path somewhere, the ./ can be omitted.
Last edited by Andy Alt; 07-08-2011 at 08:02 AM.
Reason: code revision
The script from arifsaha was without doubt leaps and bounds better than any of the others; clean, simple and cross-platform compatible. Works just as well on BSD as on GNU based toolsets. I will try to give credit whenever I use it - which I suspect will be plenty more than the three applications so far :-)
Quote:
Originally Posted by arifsaha
How about this one to get absolute path? Simpler, even local variables are not needed.
Code:
function abspath {
if [[ -d "$1" ]]
then
pushd "$1" >/dev/null
pwd
popd >/dev/null
elif [[ -e $1 ]]
then
pushd $(dirname $1) >/dev/null
echo $(pwd)/$(basename $1)
popd >/dev/null
else
echo $1 does not exist! >&2
return 127
fi
}
just one comment: instead basename and dirname you can use parameter substitution:
Code:
${var##*/} # <== basename
${var%/*} # <== dirname
_____________________________________
If someone helps you, or you approve of what's posted, click the "Add to Reputation" button, on the left of the post.
Happy with solution ... mark as SOLVED
(located in the "thread tools")
I mentioned clean and simple; for the uninitiated, that looks like voodo I prefer verbosity over terseness if the terseness comes with a reduction in readability.
actually it is not really so simple: using parameter substitution will be processed inside the shell, using basename and dirname will fork another task, will open pipe therefore it costs more, much more. If you were familiar with bash enough you should not speak about readability problems in such cases....
If you were familiar with bash enough you should not speak about readability problems in such cases...
I have never claimed to be a bash expert, and for the case of the original script, one did not need to be either, which is why I liked it For most people hacking together small scripts to get some job done it does not pay to invest time into learning the ins and outs of the various shell, which is why shell scripts should be mostly self-explanatory. Or just heavily commented But the info on why parameter substitution might prove a better fit was very interesting (for me, at least), and put the matter into another perspective. Thanks for the info - nice to know!
The script from arifsaha was without doubt leaps and bounds better than any of the others; clean, simple and cross-platform compatible. Works just as well on BSD as on GNU based toolsets. I will try to give credit whenever I use it - which I suspect will be plenty more than the three applications so far :-)
Unfortunately the directories need to exist in order for that to work. Also, you'll have to use external commands which is rather slower and require dependencies.
The realpath command was added to coreutils, as of version 8.15, I believe. Not the best solution yet -- not all *nix distros have it installed yet, and I couldn't say anything about Macs.
The realpath command was added to coreutils, as of version 8.15, I believe. Not the best solution yet -- not all *nix distros have it installed yet, and I couldn't say anything about Macs.
I just tried the suggestions from pan64, but I was unable to make it work. Can anyone change the script above and make it work with parameter substitution? I have also searched the man page for bash on the "var##" pattern, and I cannot find anything referencing it.
Quote:
Originally Posted by pan64
just one comment: instead basename and dirname you can use parameter substitution:
Code:
${var##*/} # <== basename
${var%/*} # <== dirname
_____________________________________
If someone helps you, or you approve of what's posted, click the "Add to Reputation" button, on the left of the post.
Happy with solution ... mark as SOLVED
(located in the "thread tools")
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.