[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.
What is your concern with using $PWD? If concerned about someone exporting variables to an incorrect value, you could always use $(pwd) to set the value of PWD.
Because if you write scripts using absolute paths that are not depending on a) where the script starts from, or b) from cd'ing somewhere inside the script, $PWD is irrelevant.
ta0kira has it right: to return the absolute path of a filename that is originally given with a relative path:
for example you are at a bash prompt in /dir1/dir2/dir3/dir4
Another solution is to use the external pwd command instead of the bash builtin. In the following illustration /home/c/Templates is a symlink to /home/c/d/Templates
Code:
c@CW9:~$ ls -l Templates
lrwxrwxrwx 1 c users 11 2010-06-07 11:43 Templates -> d/Template
c@CW9:~$ cd Templates
c@CW9:~/Templates$ pwd
/home/c/Templates
c@CW9:~/Templates$ echo $PWD
/home/c/Templates
c@CW9:~/Templates$ /bin/pwd
/home/c/d/Templates
I didn't know readlink was nonstandard. Thanks to the suggestions, this is what I've come up with.
Code:
#!/bin/bash
# abspath.sh
# Find absolute path of file or symbolic link without using readlink
# December 28, 2010
function absp() {
local FILE=$1
local CWD=$(pwd)
# remove trailing slash
FILE=${FILE%/}
local FBN=`basename "$FILE"`
# Remove basename to get relative path
local RP="${FILE%$FBN}"
# change dir to relative path to run pwd
cd "$RP"
# Assign present working dir to $MOVETO; pwd returns the
# absolute path
AP=$(pwd)
# Append filename to abs path
APFN=$(pwd)/$FBN
# Change back to directory we started in
cd "$CWD"
# echo -e "\n\tAbsolute path:"
# echo -e "\t$AP"
# echo -e "\n\tAbsolute path to file:"
# echo -e "\t$APFN\n"
return 0
}
absp $1
echo -e "\n\tAbsolute path:"
echo -e "\t$AP"
echo -e "\n\tAbsolute path to file:"
echo -e "\t$APFN\n"
exit 0
#!/bin/bash
# abspath.sh 0.01
# Find absolute path of file or symbolic link without using readlink
# December 28, 2010
function absp() {
# Call this function by
# VAR=`absp <filename> ap|apfn>` # backticks required
# ap will return absolute path; apfn will return absolute path with filename
local FILE=$1
local CWD=$(pwd)
# remove trailing slash
FILE=${FILE%/}
local FBN=`basename "$FILE"`
# Remove basename to get relative path
local RP="${FILE%$FBN}"
# change dir to relative path to run pwd
cd "$RP"
# Assign present working dir to $MOVETO; pwd returns the
# absolute path
local AP=$(pwd)
# Append filename to abs path
local APFN=$(pwd)/$FBN
# Change back to directory we started in
cd "$CWD"
case $2 in
ap)
echo "$AP"
;;
apfn)
echo "$APFN"
;;
*)
echo "NULL";return 1;break
;;
esac
return 0
}
# absp function takes two parameters; file name and ap|apfn
# This method allows different variable names for AP or APFN throughout the program
ABSOLUTE_PATH=`absp $1 ap`
ABSOLUTE_FILE=`absp $1 apfn`
echo $ABSOLUTE_PATH
echo $ABSOLUTE_FILE
exit 0
I made another change. In the previous function I posted, it has to be called three times if the absolute path, absolute path with filename, and base filename are required. That can slow things down. This method may be slightly more memory intensive, but speeds up the process.
Code:
function gfp_info() {
local FILE=$1
# save pwd to cd back to it below
local CWD=$(pwd)
# remove trailing slash
FILE=${FILE%/}
# Get the basename of the file
local file_basename=`basename "$FILE"`
# Remove basename to get relative path
# Using bash's string function instead of calling
# dirname
local RP="${FILE%$file_basename}"
# change dir to relative path
cd "$RP"
# Assign present working dir to $fileap; pwd returns the
# absolute path
local fileap=$(pwd)
# Append base filename to absolute path
local ap_with_basename=$(pwd)/$file_basename
# Change back to directory we started in
cd "$CWD"
AP="${fileap}"
APFN="${ap_with_basename}"
FBN="${file_basename}"
return 0
}
# Initialize variables used in function so they can be used globally
AP=""
APFN=""
FBN=""
gfp_info "$FILENAME"
# The three variables above will now have value.
local CWD=$(pwd) was removed and cd "$CWD" was changed to cd -
file_basename=`basename "$FILE"` was changed to file_basename="${FILE##*/}"
fileap=$(pwd) was changed to fileap=$PWD
ap_with_basename=$(pwd)/$file_basename was changed to ap_with_basename=$fileap/$file_basename or ap_with_basename=$PWD/$file_basename. In the latter case $fileap need not be used if suggestion 6 is implemented.
AP=""
APFN=""
FBN=""
were removed; these variables are created as global variables by assigning values to them in the function.
AP="${fileap}" were moved prior to cd "$CWD" in which case $fileap need not be used if suggestion 4, second option is implemented.
Incidentally ...
pwd does not return the absolute path if the path was reached via a symlink in which case pwd -P is needed:
Code:
c@CW8:~$ cd /tmp
c@CW8:/tmp$ mkdir foo
c@CW8:/tmp$ ln -s foo bar
c@CW8:/tmp$ cd bar
c@CW8:/tmp/bar$ pwd
/tmp/bar
c@CW8:/tmp/bar$ pwd -P
/tmp/foo
RP="${FILE%$file_basename}" does not generate a relative path; it extracts the directory component of the full path. A relative path is one that does not begin with "/". The same could be achieved by the common idiom RP=${FILE%/*} (the double quotes are not necessary on the RHS of an assignment "=". Strictly speaking these are not "bash string functions" but bash parameter expansions.
I was wrong about the slash, but the code you suggested assigns the basename, whereas I want everything except for the basename. Since I'm not good at explaining, allow me to illustrate:
Code:
# extracts the directory component of the full path
# local DC="${FILE%$file_basename}"
local DC="${FILE%/*}"
echo -e $c_1"FILE: $FILE"$c_reset
cd "$DC"
echo -e $c_1"DC: \"$DC\" pwd: - \"$(pwd -P)\" "$c_reset
# Assign present working dir to $fileap; pwd returns the
# absolute path
local fileap=$(pwd -P)
andy@pigeon:~/Documents$ rmw temp
FILE: temp
/home/andy/bin/rmw: line 451: cd: temp: Not a directory
DC: "temp" pwd: - "/home/andy/Documents"
`temp' -> `/home/andy/.Waste/files/temp.2011-01-26h13m11s43'
---
Code:
# extracts the directory component of the full path
local DC="${FILE%$file_basename}"
# local DC="${FILE%/*}"
echo -e $c_1"FILE: $FILE"$c_reset
cd "$DC"
echo -e $c_1"DC: \"$DC\" pwd: - \"$(pwd -P)\" "$c_reset
# Assign present working dir to $fileap; pwd returns the
# absolute path
local fileap=$(pwd -P)
function gfp_info() {
# Thanks to catkin for the massive improvements to this function
# http://www.linuxquestions.org/questions/user/catkin-444761/
local FILE=$1
# remove trailing slash
FILE=${FILE%/}
# Get the basename of the file
local file_basename="${FILE##*/}"
# extracts the directory component of the full path
local DC="${FILE%$file_basename}"
if [ $DC ]; then
cd "$DC"
fi
# Assign present working dir to $fileap; pwd returns the
# absolute path
local fileap=$(pwd -P)
# Append base filename to absolute path
local ap_with_basename=$fileap/$file_basename
# Change back to directory we started in
cd "-" &>/dev/null
AP="${fileap}"
APFN="${ap_with_basename}"
FBN="${file_basename}"
return 0
}
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.