]> code.delx.au - gnu-emacs/blobdiff - lisp/eshell/em-unix.el
Merge from emacs-23; up to 2010-06-12T17:12:15Z!cyd@stupidchicken.com.
[gnu-emacs] / lisp / eshell / em-unix.el
index 10e767745beec0814a626876733ce0f3bf1b12da..707f2ebc2ced0652c2840b535cf2ea6a3e6bf682 100644 (file)
@@ -1,7 +1,6 @@
 ;;; em-unix.el --- UNIX command aliases
 
 ;;; em-unix.el --- UNIX command aliases
 
-;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-;;   2008  Free Software Foundation, Inc.
+;; Copyright (C) 1999-2011  Free Software Foundation, Inc.
 
 ;; Author: John Wiegley <johnw@gnu.org>
 
 
 ;; Author: John Wiegley <johnw@gnu.org>
 
@@ -37,6 +36,8 @@
 ;;; Code:
 
 (require 'eshell)
 ;;; Code:
 
 (require 'eshell)
+(require 'esh-opt)
+(require 'pcomplete)
 
 ;;;###autoload
 (eshell-defgroup eshell-unix nil
 
 ;;;###autoload
 (eshell-defgroup eshell-unix nil
@@ -52,85 +53,86 @@ by name)."
   :tag "UNIX commands in Lisp"
   :group 'eshell-module)
 
   :tag "UNIX commands in Lisp"
   :group 'eshell-module)
 
-(defcustom eshell-unix-load-hook '(eshell-unix-initialize)
-  "*A list of functions to run when `eshell-unix' is loaded."
+(defcustom eshell-unix-load-hook nil
+  "A list of functions to run when `eshell-unix' is loaded."
+  :version "24.1"                      ; removed eshell-unix-initialize
   :type 'hook
   :group 'eshell-unix)
 
 (defcustom eshell-plain-grep-behavior nil
   :type 'hook
   :group 'eshell-unix)
 
 (defcustom eshell-plain-grep-behavior nil
-  "*If non-nil, standalone \"grep\" commands will behave normally.
+  "If non-nil, standalone \"grep\" commands will behave normally.
 Standalone in this context means not redirected, and not on the
 receiving side of a command pipeline."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-no-grep-available (not (eshell-search-path "grep"))
 Standalone in this context means not redirected, and not on the
 receiving side of a command pipeline."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-no-grep-available (not (eshell-search-path "grep"))
-  "*If non-nil, no grep is available on the current machine."
+  "If non-nil, no grep is available on the current machine."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-plain-diff-behavior nil
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-plain-diff-behavior nil
-  "*If non-nil, standalone \"diff\" commands will behave normally.
+  "If non-nil, standalone \"diff\" commands will behave normally.
 Standalone in this context means not redirected, and not on the
 receiving side of a command pipeline."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-plain-locate-behavior (featurep 'xemacs)
 Standalone in this context means not redirected, and not on the
 receiving side of a command pipeline."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-plain-locate-behavior (featurep 'xemacs)
-  "*If non-nil, standalone \"locate\" commands will behave normally.
+  "If non-nil, standalone \"locate\" commands will behave normally.
 Standalone in this context means not redirected, and not on the
 receiving side of a command pipeline."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-rm-removes-directories nil
 Standalone in this context means not redirected, and not on the
 receiving side of a command pipeline."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-rm-removes-directories nil
-  "*If non-nil, `rm' will remove directory entries.
+  "If non-nil, `rm' will remove directory entries.
 Otherwise, `rmdir' is required."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-rm-interactive-query (= (user-uid) 0)
 Otherwise, `rmdir' is required."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-rm-interactive-query (= (user-uid) 0)
-  "*If non-nil, `rm' will query before removing anything."
+  "If non-nil, `rm' will query before removing anything."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-mv-interactive-query (= (user-uid) 0)
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-mv-interactive-query (= (user-uid) 0)
-  "*If non-nil, `mv' will query before overwriting anything."
+  "If non-nil, `mv' will query before overwriting anything."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-mv-overwrite-files t
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-mv-overwrite-files t
-  "*If non-nil, `mv' will overwrite files without warning."
+  "If non-nil, `mv' will overwrite files without warning."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-cp-interactive-query (= (user-uid) 0)
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-cp-interactive-query (= (user-uid) 0)
-  "*If non-nil, `cp' will query before overwriting anything."
+  "If non-nil, `cp' will query before overwriting anything."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-cp-overwrite-files t
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-cp-overwrite-files t
-  "*If non-nil, `cp' will overwrite files without warning."
+  "If non-nil, `cp' will overwrite files without warning."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-ln-interactive-query (= (user-uid) 0)
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-ln-interactive-query (= (user-uid) 0)
-  "*If non-nil, `ln' will query before overwriting anything."
+  "If non-nil, `ln' will query before overwriting anything."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-ln-overwrite-files nil
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-ln-overwrite-files nil
-  "*If non-nil, `ln' will overwrite files without warning."
+  "If non-nil, `ln' will overwrite files without warning."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-default-target-is-dot nil
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-default-target-is-dot nil
-  "*If non-nil, the default destination for cp, mv or ln is `.'."
+  "If non-nil, the default destination for cp, mv or ln is `.'."
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-du-prefer-over-ange nil
   :type 'boolean
   :group 'eshell-unix)
 
 (defcustom eshell-du-prefer-over-ange nil
-  "*Use Eshell's du in ange-ftp remote directories.
+  "Use Eshell's du in ange-ftp remote directories.
 Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
   :type 'boolean
   :group 'eshell-unix)
 Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
   :type 'boolean
   :group 'eshell-unix)
@@ -145,17 +147,17 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
   (make-local-variable 'eshell-complex-commands)
   (setq eshell-complex-commands
        (append '("grep" "egrep" "fgrep" "agrep" "glimpse" "locate"
   (make-local-variable 'eshell-complex-commands)
   (setq eshell-complex-commands
        (append '("grep" "egrep" "fgrep" "agrep" "glimpse" "locate"
-                 "cat" "time" "cp" "mv" "make" "du" "diff")
+                 "cat" "time" "cp" "mv" "make" "du" "diff" "su" "sudo")
                eshell-complex-commands)))
 
 (defalias 'eshell/date     'current-time-string)
 (defalias 'eshell/basename 'file-name-nondirectory)
 (defalias 'eshell/dirname  'file-name-directory)
 
                eshell-complex-commands)))
 
 (defalias 'eshell/date     'current-time-string)
 (defalias 'eshell/basename 'file-name-nondirectory)
 (defalias 'eshell/dirname  'file-name-directory)
 
-(defvar interactive)
-(defvar preview)
-(defvar recursive)
-(defvar verbose)
+(defvar em-interactive)
+(defvar em-preview)
+(defvar em-recursive)
+(defvar em-verbose)
 
 (defun eshell/man (&rest args)
   "Invoke man, flattening the arguments appropriately."
 
 (defun eshell/man (&rest args)
   "Invoke man, flattening the arguments appropriately."
@@ -201,32 +203,26 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
            (eshell-error "rm: cannot remove `.' or `..'\n"))
       (if (and (file-directory-p (car files))
               (not (file-symlink-p (car files))))
            (eshell-error "rm: cannot remove `.' or `..'\n"))
       (if (and (file-directory-p (car files))
               (not (file-symlink-p (car files))))
-         (let ((dir (file-name-as-directory (car files))))
-           (eshell-remove-entries dir
-                                  (mapcar
-                                   (function
-                                    (lambda (file)
-                                      (concat dir file)))
-                                   (directory-files dir)))
-           (if verbose
+         (progn
+           (if em-verbose
                (eshell-printn (format "rm: removing directory `%s'"
                                       (car files))))
            (unless
                (eshell-printn (format "rm: removing directory `%s'"
                                       (car files))))
            (unless
-               (or preview
-                   (and interactive
+               (or em-preview
+                   (and em-interactive
                         (not (y-or-n-p
                               (format "rm: remove directory `%s'? "
                                       (car files))))))
                         (not (y-or-n-p
                               (format "rm: remove directory `%s'? "
                                       (car files))))))
-             (eshell-funcalln 'delete-directory (car files))))
-       (if verbose
+             (eshell-funcalln 'delete-directory (car files) t t)))
+       (if em-verbose
            (eshell-printn (format "rm: removing file `%s'"
                                   (car files))))
            (eshell-printn (format "rm: removing file `%s'"
                                   (car files))))
-       (unless (or preview
-                   (and interactive
+       (unless (or em-preview
+                   (and em-interactive
                         (not (y-or-n-p
                               (format "rm: remove `%s'? "
                                       (car files))))))
                         (not (y-or-n-p
                               (format "rm: remove `%s'? "
                                       (car files))))))
-         (eshell-funcalln 'delete-file (car files)))))
+         (eshell-funcalln 'delete-file (car files) t))))
     (setq files (cdr files))))
 
 (defun eshell/rm (&rest args)
     (setq files (cdr files))))
 
 (defun eshell/rm (&rest args)
@@ -239,21 +235,21 @@ argument."
    "rm" args
    '((?h "help" nil nil "show this usage screen")
      (?f "force" nil force-removal "force removal")
    "rm" args
    '((?h "help" nil nil "show this usage screen")
      (?f "force" nil force-removal "force removal")
-     (?i "interactive" nil interactive "prompt before any removal")
-     (?n "preview" nil preview "don't change anything on disk")
-     (?r "recursive" nil recursive
+     (?i "interactive" nil em-interactive "prompt before any removal")
+     (?n "preview" nil em-preview "don't change anything on disk")
+     (?r "recursive" nil em-recursive
         "remove the contents of directories recursively")
         "remove the contents of directories recursively")
-     (?R nil nil recursive "(same)")
-     (?v "verbose" nil verbose "explain what is being done")
+     (?R nil nil em-recursive "(same)")
+     (?v "verbose" nil em-verbose "explain what is being done")
      :preserve-args
      :external "rm"
      :show-usage
      :usage "[OPTION]... FILE...
 Remove (unlink) the FILE(s).")
      :preserve-args
      :external "rm"
      :show-usage
      :usage "[OPTION]... FILE...
 Remove (unlink) the FILE(s).")
-   (unless interactive
-     (setq interactive eshell-rm-interactive-query))
-   (if (and force-removal interactive)
-       (setq interactive nil))
+   (unless em-interactive
+     (setq em-interactive eshell-rm-interactive-query))
+   (if (and force-removal em-interactive)
+       (setq em-interactive nil))
    (while args
      (let ((entry (if (stringp (car args))
                      (directory-file-name (car args))
    (while args
      (let ((entry (if (stringp (car args))
                      (directory-file-name (car args))
@@ -262,37 +258,37 @@ Remove (unlink) the FILE(s).")
                      (car args)))))
        (cond
        ((bufferp entry)
                      (car args)))))
        (cond
        ((bufferp entry)
-        (if verbose
+        (if em-verbose
             (eshell-printn (format "rm: removing buffer `%s'" entry)))
             (eshell-printn (format "rm: removing buffer `%s'" entry)))
-        (unless (or preview
-                    (and interactive
+        (unless (or em-preview
+                    (and em-interactive
                          (not (y-or-n-p (format "rm: delete buffer `%s'? "
                                                 entry)))))
           (eshell-funcalln 'kill-buffer entry)))
        ((eshell-processp entry)
                          (not (y-or-n-p (format "rm: delete buffer `%s'? "
                                                 entry)))))
           (eshell-funcalln 'kill-buffer entry)))
        ((eshell-processp entry)
-        (if verbose
+        (if em-verbose
             (eshell-printn (format "rm: killing process `%s'" entry)))
             (eshell-printn (format "rm: killing process `%s'" entry)))
-        (unless (or preview
-                    (and interactive
+        (unless (or em-preview
+                    (and em-interactive
                          (not (y-or-n-p (format "rm: kill process `%s'? "
                                                 entry)))))
           (eshell-funcalln 'kill-process entry)))
        ((symbolp entry)
                          (not (y-or-n-p (format "rm: kill process `%s'? "
                                                 entry)))))
           (eshell-funcalln 'kill-process entry)))
        ((symbolp entry)
-        (if verbose
+        (if em-verbose
             (eshell-printn (format "rm: uninterning symbol `%s'" entry)))
         (unless
             (eshell-printn (format "rm: uninterning symbol `%s'" entry)))
         (unless
-            (or preview
-                (and interactive
+            (or em-preview
+                (and em-interactive
                      (not (y-or-n-p (format "rm: unintern symbol `%s'? "
                                             entry)))))
           (eshell-funcalln 'unintern entry)))
        ((stringp entry)
         (if (and (file-directory-p entry)
                  (not (file-symlink-p entry)))
                      (not (y-or-n-p (format "rm: unintern symbol `%s'? "
                                             entry)))))
           (eshell-funcalln 'unintern entry)))
        ((stringp entry)
         (if (and (file-directory-p entry)
                  (not (file-symlink-p entry)))
-            (if (or recursive
+            (if (or em-recursive
                     eshell-rm-removes-directories)
                     eshell-rm-removes-directories)
-                (if (or preview
-                        (not interactive)
+                (if (or em-preview
+                        (not em-interactive)
                         (y-or-n-p
                          (format "rm: descend into directory `%s'? "
                                  entry)))
                         (y-or-n-p
                          (format "rm: descend into directory `%s'? "
                                  entry)))
@@ -337,8 +333,6 @@ Remove the DIRECTORY(ies), if they are empty.")
 (put 'eshell/rmdir 'eshell-no-numeric-conversions t)
 
 (defvar no-dereference)
 (put 'eshell/rmdir 'eshell-no-numeric-conversions t)
 
 (defvar no-dereference)
-(defvar preview)
-(defvar verbose)
 
 (defvar eshell-warn-dot-directories t)
 
 
 (defvar eshell-warn-dot-directories t)
 
@@ -346,9 +340,9 @@ Remove the DIRECTORY(ies), if they are empty.")
   "Shuffle around some filesystem entries, using FUNC to do the work."
   (let ((attr-target (eshell-file-attributes target))
        (is-dir (or (file-directory-p target)
   "Shuffle around some filesystem entries, using FUNC to do the work."
   (let ((attr-target (eshell-file-attributes target))
        (is-dir (or (file-directory-p target)
-                   (and preview (not eshell-warn-dot-directories))))
+                   (and em-preview (not eshell-warn-dot-directories))))
        attr)
        attr)
-    (if (and (not preview) (not is-dir)
+    (if (and (not em-preview) (not is-dir)
             (> (length files) 1))
        (error "%s: when %s multiple files, last argument must be a directory"
               command action))
             (> (length files) 1))
        (error "%s: when %s multiple files, last argument must be a directory"
               command action))
@@ -385,7 +379,7 @@ Remove the DIRECTORY(ies), if they are empty.")
                   (not (memq func '(make-symbolic-link
                                     add-name-to-file))))
              (if (and (eq func 'copy-file)
                   (not (memq func '(make-symbolic-link
                                     add-name-to-file))))
              (if (and (eq func 'copy-file)
-                      (not recursive))
+                      (not em-recursive))
                  (eshell-error (format "%s: %s: omitting directory\n"
                                        command (car files)))
                (let (eshell-warn-dot-directories)
                  (eshell-error (format "%s: %s: omitting directory\n"
                                        command (car files)))
                (let (eshell-warn-dot-directories)
@@ -403,11 +397,11 @@ Remove the DIRECTORY(ies), if they are empty.")
                                             (expand-file-name target)))))))
                      (apply 'eshell-funcalln func source target args)
                  (unless (file-directory-p target)
                                             (expand-file-name target)))))))
                      (apply 'eshell-funcalln func source target args)
                  (unless (file-directory-p target)
-                   (if verbose
+                   (if em-verbose
                        (eshell-printn
                         (format "%s: making directory %s"
                                 command target)))
                        (eshell-printn
                         (format "%s: making directory %s"
                                 command target)))
-                   (unless preview
+                   (unless em-preview
                      (eshell-funcalln 'make-directory target)))
                  (apply 'eshell-shuffle-files
                         command action
                      (eshell-funcalln 'make-directory target)))
                  (apply 'eshell-shuffle-files
                         command action
@@ -418,16 +412,16 @@ Remove the DIRECTORY(ies), if they are empty.")
                          (directory-files source))
                         target func t args)
                  (when (eq func 'rename-file)
                          (directory-files source))
                         target func t args)
                  (when (eq func 'rename-file)
-                   (if verbose
+                   (if em-verbose
                        (eshell-printn
                         (format "%s: deleting directory %s"
                                 command source)))
                        (eshell-printn
                         (format "%s: deleting directory %s"
                                 command source)))
-                   (unless preview
+                   (unless em-preview
                      (eshell-funcalln 'delete-directory source))))))
                      (eshell-funcalln 'delete-directory source))))))
-           (if verbose
+           (if em-verbose
                (eshell-printn (format "%s: %s -> %s" command
                                       source target)))
                (eshell-printn (format "%s: %s -> %s" command
                                       source target)))
-           (unless preview
+           (unless em-preview
              (if (and no-dereference
                       (setq link (file-symlink-p source)))
                  (progn
              (if (and no-dereference
                       (setq link (file-symlink-p source)))
                  (progn
@@ -452,7 +446,7 @@ Remove the DIRECTORY(ies), if they are empty.")
     (if (file-exists-p archive)
        (setq tar-args (concat "u" tar-args))
       (setq tar-args (concat "c" tar-args)))
     (if (file-exists-p archive)
        (setq tar-args (concat "u" tar-args))
       (setq tar-args (concat "c" tar-args)))
-    (if verbose
+    (if em-verbose
        (setq tar-args (concat "v" tar-args)))
     (if (equal command "mv")
        (setq tar-args (concat "--remove-files -" tar-args)))
        (setq tar-args (concat "v" tar-args)))
     (if (equal command "mv")
        (setq tar-args (concat "--remove-files -" tar-args)))
@@ -485,7 +479,7 @@ Remove the DIRECTORY(ies), if they are empty.")
         (eshell-shuffle-files
          ,command ,action args target ,func nil
          ,@(append
         (eshell-shuffle-files
          ,command ,action args target ,func nil
          ,@(append
-            `((if (and (or interactive
+            `((if (and (or em-interactive
                            ,query-var)
                        (not force))
                   1 (or force ,force-var)))
                            ,query-var)
                        (not force))
                   1 (or force ,force-var)))
@@ -499,11 +493,11 @@ Remove the DIRECTORY(ies), if they are empty.")
    "mv" args
    '((?f "force" nil force
         "remove existing destinations, never prompt")
    "mv" args
    '((?f "force" nil force
         "remove existing destinations, never prompt")
-     (?i "interactive" nil interactive
+     (?i "interactive" nil em-interactive
         "request confirmation if target already exists")
         "request confirmation if target already exists")
-     (?n "preview" nil preview
+     (?n "preview" nil em-preview
         "don't change anything on disk")
         "don't change anything on disk")
-     (?v "verbose" nil verbose
+     (?v "verbose" nil em-verbose
         "explain what is being done")
      (nil "help" nil nil "show this usage screen")
      :preserve-args
         "explain what is being done")
      (nil "help" nil nil "show this usage screen")
      :preserve-args
@@ -530,15 +524,15 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
         "preserve links")
      (?f "force" nil force
         "remove existing destinations, never prompt")
         "preserve links")
      (?f "force" nil force
         "remove existing destinations, never prompt")
-     (?i "interactive" nil interactive
+     (?i "interactive" nil em-interactive
         "request confirmation if target already exists")
         "request confirmation if target already exists")
-     (?n "preview" nil preview
+     (?n "preview" nil em-preview
         "don't change anything on disk")
      (?p "preserve" nil preserve
         "preserve file attributes if possible")
         "don't change anything on disk")
      (?p "preserve" nil preserve
         "preserve file attributes if possible")
-     (?R "recursive" nil recursive
+     (?R "recursive" nil em-recursive
         "copy directories recursively")
         "copy directories recursively")
-     (?v "verbose" nil verbose
+     (?v "verbose" nil em-verbose
         "explain what is being done")
      (nil "help" nil nil "show this usage screen")
      :preserve-args
         "explain what is being done")
      (nil "help" nil nil "show this usage screen")
      :preserve-args
@@ -548,7 +542,7 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
    or:  cp [OPTION]... SOURCE... DIRECTORY
 Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
    (if archive
    or:  cp [OPTION]... SOURCE... DIRECTORY
 Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
    (if archive
-       (setq preserve t no-dereference t recursive t))
+       (setq preserve t no-dereference t em-recursive t))
    (eshell-mvcpln-template "cp" "copying" 'copy-file
                           eshell-cp-interactive-query
                           eshell-cp-overwrite-files preserve)))
    (eshell-mvcpln-template "cp" "copying" 'copy-file
                           eshell-cp-interactive-query
                           eshell-cp-overwrite-files preserve)))
@@ -562,12 +556,12 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
    '((?h "help" nil nil "show this usage screen")
      (?s "symbolic" nil symbolic
         "make symbolic links instead of hard links")
    '((?h "help" nil nil "show this usage screen")
      (?s "symbolic" nil symbolic
         "make symbolic links instead of hard links")
-     (?i "interactive" nil interactive
+     (?i "interactive" nil em-interactive
         "request confirmation if target already exists")
      (?f "force" nil force "remove existing destinations, never prompt")
         "request confirmation if target already exists")
      (?f "force" nil force "remove existing destinations, never prompt")
-     (?n "preview" nil preview
+     (?n "preview" nil em-preview
         "don't change anything on disk")
         "don't change anything on disk")
-     (?v "verbose" nil verbose "explain what is being done")
+     (?v "verbose" nil em-verbose "explain what is being done")
      :preserve-args
      :external "ln"
      :show-usage
      :preserve-args
      :external "ln"
      :show-usage
@@ -594,7 +588,7 @@ symlink, then revert to the system's definition of cat."
   (setq args (eshell-stringify-list (eshell-flatten-list args)))
   (if (or eshell-in-pipeline-p
          (catch 'special
   (setq args (eshell-stringify-list (eshell-flatten-list args)))
   (if (or eshell-in-pipeline-p
          (catch 'special
-           (eshell-for arg args
+           (dolist (arg args)
              (unless (or (and (stringp arg)
                               (> (length arg) 0)
                               (eq (aref arg 0) ?-))
              (unless (or (and (stringp arg)
                               (> (length arg) 0)
                               (eq (aref arg 0) ?-))
@@ -617,12 +611,12 @@ symlink, then revert to the system's definition of cat."
        :show-usage
        :usage "[OPTION] FILE...
 Concatenate FILE(s), or standard input, to standard output.")
        :show-usage
        :usage "[OPTION] FILE...
 Concatenate FILE(s), or standard input, to standard output.")
-     (eshell-for file args
+     (dolist (file args)
        (if (string= file "-")
           (throw 'eshell-external
                  (eshell-external-command "cat" args))))
      (let ((curbuf (current-buffer)))
        (if (string= file "-")
           (throw 'eshell-external
                  (eshell-external-command "cat" args))))
      (let ((curbuf (current-buffer)))
-       (eshell-for file args
+       (dolist (file args)
         (with-temp-buffer
           (insert-file-contents file)
           (goto-char (point-min))
         (with-temp-buffer
           (insert-file-contents file)
           (goto-char (point-min))
@@ -667,8 +661,7 @@ Concatenate FILE(s), or standard input, to standard output.")
   "In Occur mode, go to the occurrence whose line you click on."
   (interactive "e")
   (let (pos)
   "In Occur mode, go to the occurrence whose line you click on."
   (interactive "e")
   (let (pos)
-    (save-excursion
-      (set-buffer (window-buffer (posn-window (event-end event))))
+    (with-current-buffer (window-buffer (posn-window (event-end event)))
       (save-excursion
        (goto-char (posn-point (event-end event)))
        (setq pos (occur-mode-find-occurrence))))
       (save-excursion
        (goto-char (posn-point (event-end event)))
        (setq pos (occur-mode-find-occurrence))))
@@ -859,10 +852,9 @@ external command."
   (let ((ext-du (eshell-search-path "du")))
     (if (and ext-du
             (not (catch 'have-ange-path
   (let ((ext-du (eshell-search-path "du")))
     (if (and ext-du
             (not (catch 'have-ange-path
-                   (eshell-for arg args
-                     (if (eq (find-file-name-handler (expand-file-name arg)
-                                                     'directory-files)
-                             'ange-ftp-hook-function)
+                   (dolist (arg args)
+                     (if (string-equal
+                          (file-remote-p (expand-file-name arg) 'method) "ftp")
                          (throw 'have-ange-path t))))))
        (throw 'eshell-replace-command
               (eshell-parse-command ext-du args))
                          (throw 'have-ange-path t))))))
        (throw 'eshell-replace-command
               (eshell-parse-command ext-du args))
@@ -920,9 +912,7 @@ Summarize disk usage of each FILE, recursively for directories.")
 (defvar eshell-time-start nil)
 
 (defun eshell-show-elapsed-time ()
 (defvar eshell-time-start nil)
 
 (defun eshell-show-elapsed-time ()
-  (let ((elapsed (format "%.3f secs\n"
-                        (- (eshell-time-to-seconds (current-time))
-                           eshell-time-start))))
+  (let ((elapsed (format "%.3f secs\n" (- (float-time) eshell-time-start))))
     (set-text-properties 0 (length elapsed) '(face bold) elapsed)
     (eshell-interactive-print elapsed))
   (remove-hook 'eshell-post-command-hook 'eshell-show-elapsed-time t))
     (set-text-properties 0 (length elapsed) '(face bold) elapsed)
     (eshell-interactive-print elapsed))
   (remove-hook 'eshell-post-command-hook 'eshell-show-elapsed-time t))
@@ -948,7 +938,7 @@ Summarize disk usage of each FILE, recursively for directories.")
        :show-usage
        :usage "COMMAND...
 Show wall-clock time elapsed during execution of COMMAND.")
        :show-usage
        :usage "COMMAND...
 Show wall-clock time elapsed during execution of COMMAND.")
-     (setq eshell-time-start (eshell-time-to-seconds (current-time)))
+     (setq eshell-time-start (float-time))
      (add-hook 'eshell-post-command-hook 'eshell-show-elapsed-time nil t)
      ;; after setting
      (throw 'eshell-replace-command
      (add-hook 'eshell-post-command-hook 'eshell-show-elapsed-time nil t)
      ;; after setting
      (throw 'eshell-replace-command
@@ -957,7 +947,9 @@ Show wall-clock time elapsed during execution of COMMAND.")
                                  (eshell-stringify-list
                                   (eshell-flatten-list (cdr time-args))))))))
 
                                  (eshell-stringify-list
                                   (eshell-flatten-list (cdr time-args))))))))
 
-(defalias 'eshell/whoami 'user-login-name)
+(defun eshell/whoami (&rest args)
+  "Make \"whoami\" Tramp aware."
+  (or (file-remote-p default-directory 'user) (user-login-name)))
 
 (defvar eshell-diff-window-config nil)
 
 
 (defvar eshell-diff-window-config nil)
 
@@ -1043,11 +1035,86 @@ Show wall-clock time elapsed during execution of COMMAND.")
 
 (put 'eshell/occur 'eshell-no-numeric-conversions t)
 
 
 (put 'eshell/occur 'eshell-no-numeric-conversions t)
 
+;; Pacify the byte-compiler.
+(defvar tramp-default-proxies-alist)
+
+(defun eshell/su (&rest args)
+  "Alias \"su\" to call Tramp."
+  (require 'tramp)
+  (setq args (eshell-stringify-list (eshell-flatten-list args)))
+  (let ((orig-args (copy-tree args)))
+    (eshell-eval-using-options
+     "su" args
+     '((?h "help" nil nil "show this usage screen")
+       (?l "login" nil login "provide a login environment")
+       (?  nil nil login "provide a login environment")
+       :usage "[- | -l | --login] [USER]
+Become another USER during a login session.")
+     (throw 'eshell-replace-command
+           (let ((user "root")
+                 (host (or (file-remote-p default-directory 'host)
+                           "localhost"))
+                 (dir (or (file-remote-p default-directory 'localname)
+                          (expand-file-name default-directory))))
+             (dolist (arg args)
+               (if (string-equal arg "-") (setq login t) (setq user arg)))
+             ;; `eshell-eval-using-options' does not handle "-".
+             (if (member "-" orig-args) (setq login t))
+             (if login (setq dir "~/"))
+             (if (and (file-remote-p default-directory)
+                      (or
+                       (not (string-equal
+                             "su" (file-remote-p default-directory 'method)))
+                       (not (string-equal
+                             user (file-remote-p default-directory 'user)))))
+                 (add-to-list
+                  'tramp-default-proxies-alist
+                  (list host user (file-remote-p default-directory))))
+             (eshell-parse-command
+              "cd" (list (format "/su:%s@%s:%s" user host dir))))))))
+
+(put 'eshell/su 'eshell-no-numeric-conversions t)
+
+(defun eshell/sudo (&rest args)
+  "Alias \"sudo\" to call Tramp."
+  (require 'tramp)
+  (setq args (eshell-stringify-list (eshell-flatten-list args)))
+  (let ((orig-args (copy-tree args)))
+    (eshell-eval-using-options
+     "sudo" args
+     '((?h "help" nil nil "show this usage screen")
+       (?u "user" t user "execute a command as another USER")
+       :show-usage
+       :usage "[(-u | --user) USER] COMMAND
+Execute a COMMAND as the superuser or another USER.")
+     (throw 'eshell-external
+           (let ((user (or user "root"))
+                 (host (or (file-remote-p default-directory 'host)
+                           "localhost"))
+                 (dir (or (file-remote-p default-directory 'localname)
+                          (expand-file-name default-directory))))
+             ;; `eshell-eval-using-options' reads options of COMMAND.
+             (while (and (stringp (car orig-args))
+                         (member (car orig-args) '("-u" "--user")))
+               (setq orig-args (cddr orig-args)))
+             (if (and (file-remote-p default-directory)
+                      (or
+                       (not (string-equal
+                             "sudo" (file-remote-p default-directory 'method)))
+                       (not (string-equal
+                             user (file-remote-p default-directory 'user)))))
+                 (add-to-list
+                  'tramp-default-proxies-alist
+                  (list host user (file-remote-p default-directory))))
+             (let ((default-directory (format "/sudo:%s@%s:%s" user host dir)))
+               (eshell-named-command (car orig-args) (cdr orig-args))))))))
+
+(put 'eshell/sudo 'eshell-no-numeric-conversions t)
+
 (provide 'em-unix)
 
 ;; Local Variables:
 ;; generated-autoload-file: "esh-groups.el"
 ;; End:
 
 (provide 'em-unix)
 
 ;; Local Variables:
 ;; generated-autoload-file: "esh-groups.el"
 ;; End:
 
-;; arch-tag: 2462edd2-a76a-4cf2-897d-92e9a82ac1c9
 ;;; em-unix.el ends here
 ;;; em-unix.el ends here