;;; 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>
;;; Code:
(require 'eshell)
+(require 'esh-opt)
+(require 'pcomplete)
;;;###autoload
(eshell-defgroup eshell-unix nil
: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
- "*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"))
- "*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
- "*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)
- "*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
- "*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)
- "*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)
- "*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
- "*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)
- "*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
- "*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)
- "*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
- "*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
- "*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
- "*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)
(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)
-(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."
(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
- (or preview
- (and interactive
+ (or em-preview
+ (and em-interactive
(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))))
- (unless (or preview
- (and interactive
+ (unless (or em-preview
+ (and em-interactive
(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)
"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")
- (?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).")
- (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))
(car args)))))
(cond
((bufferp entry)
- (if verbose
+ (if em-verbose
(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)
- (if verbose
+ (if em-verbose
(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)
- (if verbose
+ (if em-verbose
(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)))
- (if (or recursive
+ (if (or em-recursive
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)))
(put 'eshell/rmdir 'eshell-no-numeric-conversions t)
(defvar no-dereference)
-(defvar preview)
-(defvar verbose)
(defvar eshell-warn-dot-directories t)
"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)
- (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))
(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)
(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)))
- (unless preview
+ (unless em-preview
(eshell-funcalln 'make-directory target)))
(apply 'eshell-shuffle-files
command action
(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)))
- (unless preview
+ (unless em-preview
(eshell-funcalln 'delete-directory source))))))
- (if verbose
+ (if em-verbose
(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 (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)))
(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)))
"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")
- (?n "preview" nil preview
+ (?n "preview" nil em-preview
"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
"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")
- (?n "preview" nil preview
+ (?n "preview" nil em-preview
"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")
- (?v "verbose" nil verbose
+ (?v "verbose" nil em-verbose
"explain what is being done")
(nil "help" nil nil "show this usage screen")
:preserve-args
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)))
'((?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")
- (?n "preview" nil preview
+ (?n "preview" nil em-preview
"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
(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) ?-))
: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)))
- (eshell-for file args
+ (dolist (file args)
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
"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))))
(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))
(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))
: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
(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)
(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:
-;; arch-tag: 2462edd2-a76a-4cf2-897d-92e9a82ac1c9
;;; em-unix.el ends here