I want to transform "/foo/bar/.." to "/foo"
Is there a bash command which does this?
I want to transform "/foo/bar/.." to "/foo"
Is there a bash command which does this?
Try realpath
. Bonus: it's available as a bash command and in the standard linux C libraries.
Update: realpath
is not part of the standard distribution; we'd been using it for so long that I didn't think to check! Below is the source in its entirety, hereby donated to the public domain.
// realpath.c: display the absolute path to a file or directory.
// Adam Liss, August, 2007
// This program is provided "as-is" to the public domain, without express or
// implied warranty, for any non-profit use, provided this notice is maintained.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <limits.h>
static char *s_pMyName;
void usage(void);
int main(int argc, char *argv[])
{
char
sPath[PATH_MAX];
s_pMyName = strdup(basename(argv[0]));
if (argc < 2)
usage();
printf("%s\n", realpath(argv[1], sPath));
return 0;
}
void usage(void)
{
fprintf(stderr, "usage: %s PATH\n", s_pMyName);
exit(1);
}
I don't know if there is a direct bash command to do this, but I usually do
normalDir=`cd "${dirToNormalize}";pwd`
echo ${normalDir}
and it works well.
if you're wanting to chomp part of a filename from the path, "dirname" and "basename" are your friends, and "realpath" is handy too.
$ dirname /foo/bar/baz
/foo/bar
$ basename /foo/bar/baz
baz
$ dirname $( dirname /foo/bar/baz ))
/foo
$ realpath ../foo
../foo: No such file or directory
$ realpath /tmp/../tmp/../tmp
/tmp
Edit
Realpath appears not to be standard issue.
The closest you can get with the stock standard is
readlink -f /path/here/..
Realpath appears to come from debian, and is not part of coreutils: http://packages.debian.org/unstable/utils/realpath Which was originally part of the DWWW package.
( also available on gentoo as app-admin/realpath )
readlink -m /path/there/../../
Works the same as
realpath -s /path/here/../../
in that it doesn't need the path to actually exist to normalise it.
Talkative, and a bit late answer. I need to write one since I'm stuck on older RHEL4/5. I handles absolute and relative links, and simplifies //, /./ and somedir/../ entries.
test -x /usr/bin/readlink || readlink () {
echo $(/bin/ls -l $1 | /bin/cut -d'>' -f 2)
}
test -x /usr/bin/realpath || realpath () {
local PATH=/bin:/usr/bin
local inputpath=$1
local changemade=1
while [ $changemade -ne 0 ]
do
changemade=0
local realpath=""
local token=
for token in ${inputpath//\// }
do
case $token in
""|".") # noop
;;
"..") # up one directory
changemade=1
realpath=$(dirname $realpath)
;;
*)
if [ -h $realpath/$token ]
then
changemade=1
target=`readlink $realpath/$token`
if [ "${target:0:1}" = '/' ]
then
realpath=$target
else
realpath="$realpath/$target"
fi
else
realpath="$realpath/$token"
fi
;;
esac
done
inputpath=$realpath
done
echo $realpath
}
mkdir -p /tmp/bar
(cd /tmp ; ln -s /tmp/bar foo; ln -s ../.././usr /tmp/bar/link2usr)
echo `realpath /tmp/foo`
Perhaps this works as well, and is portable:
python -c "import os,sys; print os.path.realpath(sys.argv[1])"