bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ca - New bash command proposal


From: Rolf Brudeseth
Subject: ca - New bash command proposal
Date: Wed, 11 Feb 2009 22:38:10 -0600
User-agent: Thunderbird 2.0.0.19 (X11/20090105)

I would like to propose a new command for bash:

ca [path]

It returns the canonical path based on the current working directory and entered path.


If the current working directory has been traversed through a symbolic link, then listing a higher level path using dotdot's do not always show I am looking for. Below is a trivial example:

rolfb@otto:~/test$ ls -lR
.:
total 8
drwxr-xr-x 3 rolfb rolfb 4096 2009-02-05 23:59 A
drwxr-xr-x 2 rolfb rolfb 4096 2009-02-06 00:09 B

./A:
total 4
-rw-r--r-- 1 rolfb rolfb    0 2009-02-05 23:59 a
drwxr-xr-x 2 rolfb rolfb 4096 2009-02-05 23:58 AA

./A/AA:
total 0

./B:
total 0
-rw-r--r-- 1 rolfb rolfb 0 2009-02-05 23:59 b
lrwxrwxrwx 1 rolfb rolfb 7 2009-02-06 00:09 BB -> ../A/AA

~/test$ cd B/BB

### No this is not what I was looking for

~/test/B/BB$ ls -l ..
total 4
-rw-r--r-- 1 rolfb rolfb    0 2009-02-05 23:59 a
drwxr-xr-x 2 rolfb rolfb 4096 2009-02-05 23:58 AA

~/test/B/BB$ ls ../b
ls: cannot access ../b: No such file or directory

### This is what I wanted to see

~/test/B/BB$ ca ..
/home/rolfb/test/B

~/test/B/BB$ ca ..|xargs ls -l
total 0
-rw-r--r-- 1 rolfb rolfb 0 2009-02-05 23:59 b
lrwxrwxrwx 1 rolfb rolfb 7 2009-02-06 00:09 BB -> ../A/AA

~/test/B/BB$ ca ../b
/home/rolfb/test/B/b

~/test/B/BB$ ca ../b|xargs ls -l
-rw-r--r-- 1 rolfb rolfb 0 2009-02-05 23:59 /home/rolfb/test/B/b

### System config

~/test/B/BB$ uname -a
Linux otto 2.6.27-11-generic #1 SMP Thu Jan 29 19:24:39 UTC 2009 i686 GNU/Linux

~/test/B/BB$ bash --version
GNU bash, version 3.2.39(1)-release (i486-pc-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.

~/test/B/BB$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=8.10
DISTRIB_CODENAME=intrepid
DISTRIB_DESCRIPTION="Ubuntu 8.10"


I have not done any shell, glibc or kernel development in the past and have two minor items I am a little uncertain about; free versus FREE, and the _is_cygdrive call. But unless there is an interest in this command, that will be a mute point.


The files I modified:
/home/rolfb/bash/bash-3.2# find . -type f -name "*orig"
./bash/builtins/builtext.h.orig
./bash/builtins/cd.def.orig
./bash/builtins/builtins.c.orig
./bash/externs.h.orig
./bash/lib/sh/pathcanon.c.orig



/home/rolfb/bash/bash-3.2# diff -u bash/externs.h.orig bash/externs.h
--- bash/externs.h.orig    2006-07-27 20:40:49.000000000 -0500
+++ bash/externs.h    2009-02-11 19:34:25.000000000 -0600
@@ -214,6 +214,7 @@
#define PATH_CHECKEXISTS    0x0002
#define PATH_HARDPATH        0x0004
#define PATH_NOALLOC        0x0008
+#define PATH_NOTDIRONLY        0x0010

extern char *sh_canonpath __P((char *, int));


/home/rolfb/bash/bash-3.2# diff -u bash/builtins/builtext.h.orig bash/builtins/builtext.h
--- bash/builtins/builtext.h.orig    2009-02-10 13:43:40.000000000 -0600
+++ bash/builtins/builtext.h    2009-02-11 00:30:19.000000000 -0600
@@ -21,6 +21,8 @@
extern int caller_builtin __P((WORD_LIST *));
extern char * const caller_doc[];
#endif /* DEBUGGER */
+extern int ca_builtin __P((WORD_LIST *));
+extern char * const ca_doc[];
extern int cd_builtin __P((WORD_LIST *));
extern char * const cd_doc[];
extern int pwd_builtin __P((WORD_LIST *));


/home/rolfb/bash/bash-3.2# diff -u bash/builtins/builtins.c.orig bash/builtins/builtins.c
--- bash/builtins/builtins.c.orig    2009-02-10 13:43:40.000000000 -0600
+++ bash/builtins/builtins.c    2009-02-11 13:16:01.000000000 -0600
@@ -60,6 +60,8 @@
  { "caller", caller_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, caller_doc,
     "caller [EXPR]", (char *)NULL },
#endif /* DEBUGGER */
+  { "ca", ca_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, ca_doc,
+     "ca [path]", (char *)NULL },
  { "cd", cd_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, cd_doc,
     "cd [-L|-P] [dir]", (char *)NULL },
  { "pwd", pwd_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, pwd_doc,
@@ -329,6 +331,15 @@
  (char *)NULL
};
#endif /* DEBUGGER */
+char * const ca_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Prints the canonical path which is derived from the supplied path\n\
+    concatentated to the current working directory. If a path is not\n\
+    supplied then the canonical path is only derived from the\n\
+    current working directory."),
+#endif /* HELP_BUILTIN */
+  (char *)NULL
+};
char * const cd_doc[] = {
#if defined (HELP_BUILTIN)
N_("Change the current directory to DIR.  The variable $HOME is the\n\


/home/rolfb/bash/bash-3.2# diff -u bash/builtins/cd.def.orig bash/builtins/cd.def
--- bash/builtins/cd.def.orig    2006-07-27 20:35:36.000000000 -0500
+++ bash/builtins/cd.def    2009-02-11 21:18:25.000000000 -0600
@@ -70,6 +70,15 @@

int cdable_vars;

+$BUILTIN ca
+$FUNCTION ca_builtin
+$SHORT_DOC ca [path]
+Prints the canonical path which is derived from the supplied path
+concatentated to the current working directory. If a path is not
+supplied then the canonical path is only derived from the
+current working directory.
+$END
+
$BUILTIN cd
$FUNCTION cd_builtin
$SHORT_DOC cd [-L|-P] [dir]
@@ -314,6 +323,72 @@
  return (EXECUTION_FAILURE);
}

+/* Prints the canonical path which is derived from the supplied path
+   concatentated to the current working directory. If a path is not
+   supplied then the canonical path is only derived from the
+   current working directory. */
+int
+ca_builtin (list)
+     WORD_LIST *list;
+{
+  char *dirname, *t, *tdir;
+
+#if defined (RESTRICTED_SHELL)
+  if (restricted)
+    {
+      sh_restricted ((char *)NULL);
+      return (EXECUTION_FAILURE);
+    }
+#endif /* RESTRICTED_SHELL */
+
+  reset_internal_getopt ();
+  if (internal_getopt (list, "") != -1)
+    {
+      builtin_usage ();
+      return (EXECUTION_FAILURE);
+    }
+  list = loptend;
+
+  if (the_current_working_directory == 0)
+    {
+      t = get_working_directory ("ca");
+      FREE (t);
+    }
+
+  if (list == 0)
+    {
+      printf("%s\n", the_current_working_directory);
+    }
+  else
+    {
+      dirname = list->word->word;
+
+      tdir = (char *)NULL;
+
+      t = make_absolute (dirname, the_current_working_directory);
+
+ tdir = sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS|PATH_NOTDIRONLY);
+
+      free(t);
+
+      if (tdir == NULL)
+        {
+      if (errno)
+        builtin_error ("%s: %s", dirname, strerror (errno));
+      else
+            builtin_error ("%s: %s", dirname, "Path not found");
+          return (EXECUTION_FAILURE);
+        }
+      else
+        {
+          printf("%s\n", tdir);
+          free (tdir);
+        }
+    }
+
+  return 0;
+}
+
$BUILTIN pwd
$FUNCTION pwd_builtin
$SHORT_DOC pwd [-LP]




/home/rolfb/bash/bash-3.2# diff -u bash/lib/sh/pathcanon.c.orig bash/lib/sh/pathcanon.c
--- bash/lib/sh/pathcanon.c.orig    2005-02-22 16:40:56.000000000 -0600
+++ bash/lib/sh/pathcanon.c    2009-02-11 20:47:08.000000000 -0600
@@ -88,6 +88,24 @@
  return l;
}

+/* Return 1 if PATH is found. */
+static int
+_path_ispath (path)
+     char *path;
+{
+  int l;
+  struct stat sb;
+
+  /* This should leave errno set to the correct value. */
+  errno = 0;
+  l = stat (path, &sb) == 0;
+#if defined (__CYGWIN__)
+  if (l == 0)
+    l = _is_cygdrive (path);
+#endif
+  return l;
+}
+
/* Canonicalize PATH, and return a new path. The new path differs from PATH
   in that:
    Multple `/'s are collapsed to a single `/'.
@@ -160,12 +178,17 @@
          if (flags & PATH_CHECKDOTDOT)
        {
          char c;
+          int path_found;

          /* Make sure what we have so far corresponds to a valid
             path before we chop some of it off. */
          c = *q;
          *q = '\0';
-          if (_path_isdir (result) == 0)
+              if (flags & PATH_NOTDIRONLY)
+                path_found = _path_ispath (result);
+          else
+                path_found = _path_isdir (result);
+              if (!path_found)
            {
              if ((flags & PATH_NOALLOC) == 0)
            free (result);
@@ -198,12 +221,17 @@
      if (flags & PATH_CHECKEXISTS)
        {
          char c;
+          int path_found;

          /* Make sure what we have so far corresponds to a valid
         path before we chop some of it off. */
          c = *q;
          *q = '\0';
-          if (_path_isdir (result) == 0)
+          if (flags & PATH_NOTDIRONLY)
+            path_found = _path_ispath (result);
+          else
+            path_found = _path_isdir (result);
+          if (!path_found)
        {
          if ((flags & PATH_NOALLOC) == 0)
            free (result);

Rolf Brudeseth





reply via email to

[Prev in Thread] Current Thread [Next in Thread]