1 ;;; em-unix --- UNIX command aliases
3 ;; Copyright (C) 1999, 2000 Free Software Foundation
5 ;; This file is part of GNU Emacs.
7 ;; GNU Emacs is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; GNU Emacs is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GNU Emacs; see the file COPYING. If not, write to the
19 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 ;; Boston, MA 02111-1307, USA.
24 (eval-when-compile (require 'esh-maint))
26 (defgroup eshell-unix nil
27 "This module defines many of the more common UNIX utilities as
28 aliases implemented in Lisp. These include mv, ln, cp, rm, etc. If
29 the user passes arguments which are too complex, or are unrecognized
30 by the Lisp variant, the external version will be called (if
31 available). The only reason not to use them would be because they are
32 usually much slower. But in several cases their tight integration
33 with Eshell makes them more versatile than their traditional cousins
34 \(such as being able to use `kill' to kill Eshell background processes
36 :tag "UNIX commands in Lisp"
37 :group 'eshell-module)
41 ;; This file contains implementations of several UNIX command in Emacs
42 ;; Lisp, for several reasons:
44 ;; 1) it makes them available on all platforms where the Lisp
45 ;; functions used are available
47 ;; 2) it makes their functionality accessible and modified by the
50 ;; 3) it allows Eshell to refrain from having to invoke external
51 ;; processes for common operations.
53 (defcustom eshell-unix-load-hook '(eshell-unix-initialize)
54 "*A list of functions to run when `eshell-unix' is loaded."
58 (defcustom eshell-plain-grep-behavior nil
59 "*If non-nil, standalone \"grep\" commands will behave normally.
60 Standalone in this context means not redirected, and not on the
61 receiving side of a command pipeline."
65 (defcustom eshell-no-grep-available (not (eshell-search-path "grep"))
66 "*If non-nil, no grep is available on the current machine."
70 (defcustom eshell-plain-diff-behavior nil
71 "*If non-nil, standalone \"diff\" commands will behave normally.
72 Standalone in this context means not redirected, and not on the
73 receiving side of a command pipeline."
77 (defcustom eshell-plain-locate-behavior nil
78 "*If non-nil, standalone \"locate\" commands will behave normally.
79 Standalone in this context means not redirected, and not on the
80 receiving side of a command pipeline."
84 (defcustom eshell-rm-removes-directories nil
85 "*If non-nil, `rm' will remove directory entries.
86 Otherwise, `rmdir' is required."
90 (defcustom eshell-rm-interactive-query (= (user-uid) 0)
91 "*If non-nil, `rm' will query before removing anything."
95 (defcustom eshell-mv-interactive-query (= (user-uid) 0)
96 "*If non-nil, `mv' will query before overwriting anything."
100 (defcustom eshell-mv-overwrite-files t
101 "*If non-nil, `mv' will overwrite files without warning."
105 (defcustom eshell-cp-interactive-query (= (user-uid) 0)
106 "*If non-nil, `cp' will query before overwriting anything."
110 (defcustom eshell-cp-overwrite-files t
111 "*If non-nil, `cp' will overwrite files without warning."
115 (defcustom eshell-ln-interactive-query (= (user-uid) 0)
116 "*If non-nil, `ln' will query before overwriting anything."
120 (defcustom eshell-ln-overwrite-files t
121 "*If non-nil, `ln' will overwrite files without warning."
129 (defun eshell-unix-initialize ()
130 "Initialize the UNIX support/emulation code."
131 (make-local-hook 'eshell-post-command-hook)
132 (when (eshell-using-module 'eshell-cmpl)
133 (make-local-hook 'pcomplete-try-first-hook)
134 (add-hook 'pcomplete-try-first-hook
135 'eshell-complete-host-reference nil t)))
137 (defalias 'eshell/date 'current-time-string)
138 (defalias 'eshell/basename 'file-name-nondirectory)
139 (defalias 'eshell/dirname 'file-name-directory)
147 (defun eshell/man (&rest args)
148 "Invoke man, flattening the arguments appropriately."
149 (funcall 'man (apply 'eshell-flatten-and-stringify args)))
151 (defun eshell-remove-entries (path files &optional top-level)
153 (if (string-match "\\`\\.\\.?\\'"
154 (file-name-nondirectory (car files)))
156 (eshell-error "rm: cannot remove `.' or `..'\n"))
157 (if (and (file-directory-p (car files))
158 (not (file-symlink-p (car files))))
159 (let ((dir (file-name-as-directory (car files))))
160 (eshell-remove-entries dir
165 (directory-files dir)))
167 (eshell-printn (format "rm: removing directory `%s'"
173 (format "rm: remove directory `%s'? "
175 (eshell-funcalln 'delete-directory (car files))))
177 (eshell-printn (format "rm: removing file `%s'"
182 (format "rm: remove `%s'? "
184 (eshell-funcalln 'delete-file (car files)))))
185 (setq files (cdr files))))
187 (defun eshell/rm (&rest args)
188 "Implementation of rm in Lisp.
189 This is implemented to call either `delete-file', `kill-buffer',
190 `kill-process', or `unintern', depending on the nature of the
192 (setq args (eshell-flatten-list args))
193 (eshell-eval-using-options
195 '((?h "help" nil nil "show this usage screen")
196 (?f "force" nil force-removal "force removal")
197 (?i "interactive" nil interactive "prompt before any removal")
198 (?n "preview" nil preview "don't change anything on disk")
199 (?r "recursive" nil recursive
200 "remove the contents of directories recursively")
201 (?R nil nil recursive "(same)")
202 (?v "verbose" nil verbose "explain what is being done")
206 :usage "[OPTION]... FILE...
207 Remove (unlink) the FILE(s).")
209 (setq interactive eshell-rm-interactive-query))
210 (if (and force-removal interactive)
211 (setq interactive nil))
213 (let ((entry (if (stringp (car args))
214 (directory-file-name (car args))
215 (if (numberp (car args))
216 (number-to-string (car args))
221 (eshell-printn (format "rm: removing buffer `%s'" entry)))
224 (not (y-or-n-p (format "rm: delete buffer `%s'? "
226 (eshell-funcalln 'kill-buffer entry)))
229 (eshell-printn (format "rm: killing process `%s'" entry)))
232 (not (y-or-n-p (format "rm: kill process `%s'? "
234 (eshell-funcalln 'kill-process entry)))
237 (eshell-printn (format "rm: uninterning symbol `%s'" entry)))
241 (not (y-or-n-p (format "rm: unintern symbol `%s'? "
243 (eshell-funcalln 'unintern entry)))
245 (if (and (file-directory-p entry)
246 (not (file-symlink-p entry)))
248 eshell-rm-removes-directories)
252 (format "rm: descend into directory `%s'? "
254 (eshell-remove-entries nil (list entry) t))
255 (eshell-error (format "rm: %s: is a directory\n" entry)))
256 (eshell-remove-entries nil (list entry) t)))))
257 (setq args (cdr args)))
260 (defun eshell/mkdir (&rest args)
261 "Implementation of mkdir in Lisp."
262 (eshell-eval-using-options
264 '((?h "help" nil nil "show this usage screen")
267 :usage "[OPTION] DIRECTORY...
268 Create the DIRECTORY(ies), if they do not already exist.")
270 (eshell-funcalln 'make-directory (car args))
271 (setq args (cdr args)))
274 (defun eshell/rmdir (&rest args)
275 "Implementation of rmdir in Lisp."
276 (eshell-eval-using-options
278 '((?h "help" nil nil "show this usage screen")
281 :usage "[OPTION] DIRECTORY...
282 Remove the DIRECTORY(ies), if they are empty.")
284 (eshell-funcalln 'delete-directory (car args))
285 (setq args (cdr args)))
289 (defvar no-dereference)
293 (defvar eshell-warn-dot-directories t)
295 (defun eshell-shuffle-files (command action files target func deep &rest args)
296 "Shuffle around some filesystem entries, using FUNC to do the work."
298 (error "%s: missing destination file" command))
299 (let ((attr-target (file-attributes target))
300 (is-dir (or (file-directory-p target)
301 (and preview (not eshell-warn-dot-directories))))
303 (if (and (not preview) (not is-dir)
304 (> (length files) 1))
305 (error "%s: when %s multiple files, last argument must be a directory"
308 (setcar files (directory-file-name (car files)))
310 ((string-match "\\`\\.\\.?\\'"
311 (file-name-nondirectory (car files)))
312 (if eshell-warn-dot-directories
313 (eshell-error (format "%s: %s: omitting directory\n"
314 command (car files)))))
316 (or (not (eshell-under-windows-p))
317 (eq system-type 'ms-dos))
318 (setq attr (file-attributes (car files)))
319 (= (nth 10 attr-target) (nth 10 attr))
320 (= (nth 11 attr-target) (nth 11 attr)))
321 (eshell-error (format "%s: `%s' and `%s' are the same file\n"
322 command (car files) target)))
324 (let ((source (car files))
327 (file-name-nondirectory (car files)) target)
330 (if (and (file-directory-p source)
331 (or (not no-dereference)
332 (not (file-symlink-p source)))
333 (not (memq func '(make-symbolic-link
335 (if (and (eq func 'copy-file)
337 (eshell-error (format "%s: %s: omitting directory\n"
338 command (car files)))
339 (let (eshell-warn-dot-directories)
341 (eq func 'rename-file)
342 (= (nth 11 (file-attributes
344 (expand-file-name source))))
345 (nth 11 (file-attributes
347 (expand-file-name target))))))
348 (apply 'eshell-funcalln func source target args)
349 (unless (file-directory-p target)
352 (format "%s: making directory %s"
355 (eshell-funcalln 'make-directory target)))
356 (eshell-shuffle-files command action
360 (concat source "/" file)))
361 (directory-files source))
363 (when (eq func 'rename-file)
366 (format "%s: deleting directory %s"
369 (eshell-funcalln 'delete-directory source))))))
371 (eshell-printn (format "%s: %s -> %s" command
374 (if (and no-dereference
375 (setq link (file-symlink-p source)))
377 (apply 'eshell-funcalln 'make-symbolic-link
379 (if (eq func 'rename-file)
380 (if (and (file-directory-p source)
381 (not (file-symlink-p source)))
382 (eshell-funcalln 'delete-directory source)
383 (eshell-funcalln 'delete-file source))))
384 (apply 'eshell-funcalln func source target args)))))))
385 (setq files (cdr files)))))
387 (defun eshell-shorthand-tar-command (command args)
388 "Rewrite `cp -v dir a.tar.gz' to `tar cvzf a.tar.gz dir'."
389 (let* ((archive (car (last args)))
391 (cond ((string-match "z2" archive) "If")
392 ((string-match "gz" archive) "zf")
393 ((string-match "\\(az\\|Z\\)" archive) "Zf")
395 (if (file-exists-p archive)
396 (setq tar-args (concat "u" tar-args))
397 (setq tar-args (concat "c" tar-args)))
399 (setq tar-args (concat "v" tar-args)))
400 (if (equal command "mv")
401 (setq tar-args (concat "--remove-files -" tar-args)))
402 ;; truncate the archive name from the arguments
403 (setcdr (last args 2) nil)
404 (throw 'eshell-replace-command
405 (eshell-parse-command
406 (format "tar %s %s" tar-args archive) args))))
408 ;; this is to avoid duplicating code...
409 (defmacro eshell-mvcp-template
410 (command action func query-var force-var &optional preserve)
411 `(if (and (string-match eshell-tar-regexp (car (last args)))
412 (or (> (length args) 2)
413 (and (file-directory-p (car args))
414 (or (not no-dereference)
415 (not (file-symlink-p (car args)))))))
416 (eshell-shorthand-tar-command ,command args)
418 (if (> (length args) 1)
420 (setq target (car (last args)))
421 (setcdr (last args 2) nil))
423 (eshell-shuffle-files
424 ,command ,action args target ,func nil
426 `((if (and (or interactive
429 1 (or force ,force-var)))
434 (defun eshell/mv (&rest args)
435 "Implementation of mv in Lisp."
436 (eshell-eval-using-options
438 '((?f "force" nil force
439 "remove existing destinations, never prompt")
440 (?i "interactive" nil interactive
441 "request confirmation if target already exists")
442 (?n "preview" nil preview
443 "don't change anything on disk")
444 (?v "verbose" nil verbose
445 "explain what is being done")
446 (nil "help" nil nil "show this usage screen")
449 :usage "[OPTION]... SOURCE DEST
450 or: mv [OPTION]... SOURCE... DIRECTORY
451 Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
452 \[OPTION] DIRECTORY...")
453 (let ((no-dereference t))
454 (eshell-mvcp-template "mv" "moving" 'rename-file
455 eshell-mv-interactive-query
456 eshell-mv-overwrite-files))))
458 (defun eshell/cp (&rest args)
459 "Implementation of cp in Lisp."
460 (eshell-eval-using-options
462 '((?a "archive" nil archive
464 (?d "no-dereference" nil no-dereference
466 (?f "force" nil force
467 "remove existing destinations, never prompt")
468 (?i "interactive" nil interactive
469 "request confirmation if target already exists")
470 (?n "preview" nil preview
471 "don't change anything on disk")
472 (?p "preserve" nil preserve
473 "preserve file attributes if possible")
474 (?R "recursive" nil recursive
475 "copy directories recursively")
476 (?v "verbose" nil verbose
477 "explain what is being done")
478 (nil "help" nil nil "show this usage screen")
481 :usage "[OPTION]... SOURCE DEST
482 or: cp [OPTION]... SOURCE... DIRECTORY
483 Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
485 (setq preserve t no-dereference t recursive t))
486 (eshell-mvcp-template "cp" "copying" 'copy-file
487 eshell-cp-interactive-query
488 eshell-cp-overwrite-files preserve)))
490 (defun eshell/ln (&rest args)
491 "Implementation of ln in Lisp."
492 (eshell-eval-using-options
494 '((?h "help" nil nil "show this usage screen")
495 (?s "symbolic" nil symbolic
496 "make symbolic links instead of hard links")
497 (?i "interactive" nil interactive "request confirmation if target already exists")
498 (?f "force" nil force "remove existing destinations, never prompt")
499 (?n "preview" nil preview
500 "don't change anything on disk")
501 (?v "verbose" nil verbose "explain what is being done")
504 :usage "[OPTION]... TARGET [LINK_NAME]
505 or: ln [OPTION]... TARGET... DIRECTORY
506 Create a link to the specified TARGET with optional LINK_NAME. If there is
507 more than one TARGET, the last argument must be a directory; create links
508 in DIRECTORY to each TARGET. Create hard links by default, symbolic links
509 with '--symbolic'. When creating hard links, each TARGET must exist.")
510 (let (target no-dereference)
511 (if (> (length args) 1)
513 (setq target (car (last args)))
514 (setcdr (last args 2) nil))
516 (eshell-shuffle-files "ln" "linking" args target
519 'add-name-to-file) nil
520 (if (and (or interactive
521 eshell-ln-interactive-query)
523 1 (or force eshell-ln-overwrite-files))))
526 (defun eshell/cat (&rest args)
527 "Implementation of cat in Lisp."
528 (if eshell-in-pipeline-p
529 (throw 'eshell-replace-command
530 (eshell-parse-command "*cat" args))
531 (eshell-init-print-buffer)
532 (eshell-eval-using-options
534 '((?h "help" nil nil "show this usage screen")
537 :usage "[OPTION] FILE...
538 Concatenate FILE(s), or standard input, to standard output.")
539 (eshell-for file args
540 (if (string= file "-")
541 (throw 'eshell-external
542 (eshell-external-command "cat" args))))
543 (let ((curbuf (current-buffer)))
544 (eshell-for file args
546 (insert-file-contents file)
547 (goto-char (point-min))
549 (let ((str (buffer-substring
550 (point) (min (1+ (line-end-position))
552 (with-current-buffer curbuf
553 (eshell-buffered-print str)))
556 ;; if the file does not end in a newline, do not emit one
557 (setq eshell-ensure-newline-p nil))))
559 ;; special front-end functions for compilation-mode buffers
561 (defun eshell/make (&rest args)
562 "Use `compile' to do background makes."
563 (if (and eshell-current-subjob-p
564 (eshell-interactive-output-p))
565 (let ((compilation-process-setup-function
567 (list 'setq 'process-environment
568 (list 'quote (eshell-copy-environment))))))
569 (compile (concat "make " (eshell-flatten-and-stringify args))))
570 (throw 'eshell-replace-command
571 (eshell-parse-command "*make" args))))
573 (defun eshell-occur-mode-goto-occurrence ()
574 "Go to the occurrence the current line describes."
576 (let ((pos (occur-mode-find-occurrence)))
577 (pop-to-buffer (marker-buffer pos))
578 (goto-char (marker-position pos))))
580 (defun eshell-occur-mode-mouse-goto (event)
581 "In Occur mode, go to the occurrence whose line you click on."
585 (set-buffer (window-buffer (posn-window (event-end event))))
587 (goto-char (posn-point (event-end event)))
588 (setq pos (occur-mode-find-occurrence))
589 (setq buffer occur-buffer)))
590 (pop-to-buffer (marker-buffer pos))
591 (goto-char (marker-position pos))))
593 (defun eshell-poor-mans-grep (args)
594 "A poor version of grep that opens every file and uses `occur'.
595 This eats up memory, since it leaves the buffers open (to speed future
596 searches), and it's very slow. But, if your system has no grep
598 (save-selected-window
599 (let ((default-dir default-directory))
600 (with-current-buffer (get-buffer-create "*grep*")
601 (let ((inhibit-read-only t)
602 (default-directory default-dir))
605 (let ((files (eshell-flatten-list (cdr args)))
606 (inhibit-redisplay t)
609 (if (get-buffer "*Occur*")
610 (kill-buffer (get-buffer "*Occur*")))
613 (with-current-buffer (find-file-noselect (car files))
617 (if (get-buffer "*Occur*")
618 (with-current-buffer (get-buffer "*Occur*")
619 (setq string (buffer-string))
620 (kill-buffer (current-buffer)))))
621 (if string (insert string))
623 files (cdr files)))))
624 (setq occur-buffer (current-buffer))
625 (local-set-key [mouse-2] 'eshell-occur-mode-mouse-goto)
626 (local-set-key [(control ?c) (control ?c)]
627 'eshell-occur-mode-goto-occurrence)
628 (local-set-key [(control ?m)]
629 'eshell-occur-mode-goto-occurrence)
630 (local-set-key [return] 'eshell-occur-mode-goto-occurrence)
631 (pop-to-buffer (current-buffer) t)
632 (goto-char (point-min))
633 (resize-temp-buffer-window))))))
635 (defun eshell-grep (command args &optional maybe-use-occur)
636 "Generic service function for the various grep aliases.
637 It calls Emacs' grep utility if the command is not redirecting output,
638 and if it's not part of a command pipeline. Otherwise, it calls the
640 (if (and maybe-use-occur eshell-no-grep-available)
641 (eshell-poor-mans-grep args)
642 (if (or eshell-plain-grep-behavior
643 (not (and (eshell-interactive-output-p)
644 (not eshell-in-pipeline-p)
645 (not eshell-in-subcommand-p))))
646 (throw 'eshell-replace-command
647 (eshell-parse-command (concat "*" command) args))
648 (let* ((compilation-process-setup-function
650 (list 'setq 'process-environment
651 (list 'quote (eshell-copy-environment)))))
652 (args (mapconcat 'identity
653 (mapcar 'shell-quote-argument
654 (eshell-flatten-list args))
657 (set-text-properties 0 (length args)
659 (format "%s -n %s" command args)))
660 compilation-scroll-output)
663 (defun eshell/grep (&rest args)
664 "Use Emacs grep facility instead of calling external grep."
665 (eshell-grep "grep" args t))
667 (defun eshell/egrep (&rest args)
668 "Use Emacs grep facility instead of calling external egrep."
669 (eshell-grep "egrep" args t))
671 (defun eshell/fgrep (&rest args)
672 "Use Emacs grep facility instead of calling external fgrep."
673 (eshell-grep "fgrep" args t))
675 (defun eshell/agrep (&rest args)
676 "Use Emacs grep facility instead of calling external agrep."
677 (eshell-grep "agrep" args))
679 (defun eshell/glimpse (&rest args)
680 "Use Emacs grep facility instead of calling external glimpse."
682 (eshell-grep "glimpse" (append '("-z" "-y") args))))
684 ;; completions rules for some common UNIX commands
686 (defsubst eshell-complete-hostname ()
687 "Complete a command that wants a hostname for an argument."
688 (pcomplete-here (eshell-read-host-names)))
690 (defun eshell-complete-host-reference ()
691 "If there is a host reference, complete it."
692 (let ((arg (pcomplete-actual-arg))
694 (when (setq index (string-match "@[a-z.]*\\'" arg))
695 (setq pcomplete-stub (substring arg (1+ index))
696 pcomplete-last-completion-raw t)
697 (throw 'pcomplete-completions (eshell-read-host-names)))))
699 (defalias 'pcomplete/ftp 'eshell-complete-hostname)
700 (defalias 'pcomplete/ncftp 'eshell-complete-hostname)
701 (defalias 'pcomplete/ping 'eshell-complete-hostname)
702 (defalias 'pcomplete/rlogin 'eshell-complete-hostname)
704 (defun pcomplete/telnet ()
705 (require 'pcmpl-unix)
706 (pcomplete-opt "xl(pcmpl-unix-user-names)")
707 (eshell-complete-hostname))
709 (defun pcomplete/rsh ()
710 "Complete `rsh', which, after the user and hostname, is like xargs."
711 (require 'pcmpl-unix)
712 (pcomplete-opt "l(pcmpl-unix-user-names)")
713 (eshell-complete-hostname)
714 (pcomplete-here (funcall pcomplete-command-completion-function))
715 (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1))
716 pcomplete-default-completion-function)))
718 (defalias 'pcomplete/ssh 'pcomplete/rsh)
723 (defvar dereference-links)
725 (defvar human-readable)
727 (defvar only-one-filesystem)
730 (defsubst eshell-du-size-string (size)
731 (let* ((str (eshell-printable-size size human-readable block-size t))
733 (concat str (if (< len 8)
734 (make-string (- 8 len) ? )))))
736 (defun eshell-du-sum-directory (path depth)
737 "Summarize PATH, and its member directories."
738 (let ((entries (eshell-directory-files-and-attributes path))
741 (unless (string-match "\\`\\.\\.?\\'" (caar entries))
742 (let* ((entry (concat path (char-to-string directory-sep-char)
744 (symlink (and (stringp (cadr (car entries)))
745 (cadr (car entries)))))
746 (unless (or (and symlink (not dereference-links))
747 (and only-one-filesystem
748 (not (= only-one-filesystem
749 (nth 12 (car entries))))))
751 (setq entry symlink))
754 (if (eq t (cadr (car entries)))
755 (eshell-du-sum-directory entry (1+ depth))
756 (let ((file-size (nth 8 (car entries))))
761 (concat (eshell-du-size-string file-size)
762 entry "\n")))))))))))
763 (setq entries (cdr entries)))
764 (if (or (not max-depth)
767 (eshell-print (concat (eshell-du-size-string size)
768 (directory-file-name path) "\n")))
771 (defun eshell/du (&rest args)
772 "Implementation of \"du\" in Lisp, passing RAGS."
773 (if (eshell-search-path "du")
774 (throw 'eshell-replace-command
775 (eshell-parse-command "*du" args))
776 (eshell-eval-using-options
778 '((?a "all" nil show-all
779 "write counts for all files, not just directories")
780 (nil "block-size" t block-size
781 "use SIZE-byte blocks (i.e., --block-size SIZE)")
782 (?b "bytes" nil by-bytes
783 "print size in bytes")
784 (?c "total" nil grand-total
785 "produce a grand total")
786 (?d "max-depth" t max-depth
787 "display data only this many levels of data")
788 (?h "human-readable" 1024 human-readable
789 "print sizes in human readable format")
790 (?H "is" 1000 human-readable
791 "likewise, but use powers of 1000 not 1024")
792 (?k "kilobytes" 1024 block-size
793 "like --block-size 1024")
794 (?L "dereference" nil dereference-links
795 "dereference all symbolic links")
796 (?m "megabytes" 1048576 block-size
797 "like --block-size 1048576")
798 (?s "summarize" 0 max-depth
799 "display only a total for each argument")
800 (?x "one-file-system" nil only-one-filesystem
801 "skip directories on different filesystems")
803 "show this usage screen")
805 :usage "[OPTION]... FILE...
806 Summarize disk usage of each FILE, recursively for directories.")
808 (setq block-size (or block-size 1024)))
809 (if (and max-depth (stringp max-depth))
810 (setq max-depth (string-to-int max-depth)))
811 ;; filesystem support means nothing under Windows
812 (if (eshell-under-windows-p)
813 (setq only-one-filesystem nil))
818 (if only-one-filesystem
819 (setq only-one-filesystem
820 (nth 11 (file-attributes
821 (file-name-as-directory (car args))))))
822 (setq size (+ size (eshell-du-sum-directory
823 (directory-file-name (car args)) 0)))
824 (setq args (cdr args)))
826 (eshell-print (concat (eshell-du-size-string size)
829 (defvar eshell-time-start nil)
831 (defun eshell-show-elapsed-time ()
832 (let ((elapsed (format "%.3f secs\n"
833 (- (eshell-time-to-seconds (current-time))
834 eshell-time-start))))
835 (set-text-properties 0 (length elapsed) '(face bold) elapsed)
836 (eshell-interactive-print elapsed))
837 (remove-hook 'eshell-post-command-hook 'eshell-show-elapsed-time t))
839 (defun eshell/time (&rest args)
840 "Implementation of \"time\" in Lisp."
841 (let ((time-args (copy-alist args))
844 (while (and continue args)
845 (if (not (string-match "^-" (car args)))
848 (setcdr last-arg nil)
853 (eshell-eval-using-options
855 '((?h "help" nil nil "show this usage screen")
859 Show wall-clock time elapsed during execution of COMMAND.")
860 (setq eshell-time-start (eshell-time-to-seconds (current-time)))
861 (add-hook 'eshell-post-command-hook 'eshell-show-elapsed-time nil t)
863 (throw 'eshell-replace-command
864 (eshell-parse-command (car time-args) (cdr time-args))))))
866 (defalias 'eshell/whoami 'user-login-name)
868 (defvar eshell-diff-window-config nil)
870 (defun eshell-diff-quit ()
871 "Restore the window configuration previous to diff'ing."
873 (if eshell-diff-window-config
874 (set-window-configuration eshell-diff-window-config)))
876 (defun eshell/diff (&rest args)
877 "Alias \"diff\" to call Emacs `diff' function."
878 (if (or eshell-plain-diff-behavior
879 (not (and (eshell-interactive-output-p)
880 (not eshell-in-pipeline-p)
881 (not eshell-in-subcommand-p))))
882 (throw 'eshell-replace-command
883 (eshell-parse-command "*diff" args))
884 (setq args (eshell-flatten-list args))
885 (if (< (length args) 2)
886 (error "diff: missing operand"))
887 (let ((old (car (last args 2)))
888 (new (car (last args)))
889 (config (current-window-configuration)))
890 (if (= (length args) 2)
892 (setcdr (last args 3) nil))
894 (diff old new (eshell-flatten-and-stringify args))
895 (when (fboundp 'diff-mode)
897 (set (make-local-variable 'eshell-diff-window-config) config)
898 (local-set-key [?q] 'eshell-diff-quit)
899 (if (fboundp 'turn-on-font-lock-if-enabled)
900 (turn-on-font-lock-if-enabled))))
902 (goto-char (point-min))
905 (defun eshell/locate (&rest args)
906 "Alias \"locate\" to call Emacs `locate' function."
907 (if (or eshell-plain-locate-behavior
908 (not (and (eshell-interactive-output-p)
909 (not eshell-in-pipeline-p)
910 (not eshell-in-subcommand-p)))
911 (and (stringp (car args))
912 (string-match "^-" (car args))))
913 (throw 'eshell-replace-command
914 (eshell-parse-command "*locate" args))
915 (save-selected-window
916 (let ((locate-history-list (list (car args))))
917 (locate-with-filter (car args) (cadr args))))))
919 (defun eshell/occur (&rest args)
920 "Alias \"occur\" to call Emacs `occur' function."
921 (let ((inhibit-read-only t))
923 (error "usage: occur: (REGEXP)")
924 (occur (car args)))))
928 ;;; em-unix.el ends here