occur in the file name, they will confuse the shell. To handle these
characters, use the function @code{shell-quote-argument}:
-@defun shell-quote-argument argument
+@defun shell-quote-argument argument &optional posix
This function returns a string that represents, in shell syntax,
an argument whose actual contents are @var{argument}. It should
work reliably to concatenate the return value into a shell command
" "
(shell-quote-argument newfile))
@end example
+
+If the optional @var{posix} argument is non-@code{nil}, @var{argument}
+is quoted according to POSIX shell quoting rules, regardless of the
+system’s shell. This is useful when your shell could run on a remote
+host, which requires a POSIX shell in general.
+
+@example
+(shell-quote-argument "foo > bar" (file-remote-p default-directory))
+@end example
@end defun
@cindex quoting and unquoting command-line arguments
alphabetical (the default), or a custom sort function.
+++
-*** New values for the 'completion-auto-help' option.
+*** New values for the 'completion-auto-help' user option.
There are two new values to control the way "*Completions*" behave after
-a <tab> if completion is not unique. 'always' updates or shows
+a 'TAB' if completion is not unique. 'always' updates or shows
the "*Completions*" buffer after any attempt to complete. 'visual' is
like 'always', but only update the completions if they are already
visible. The default value 't' always hides the completion buffer after
This option limits the height of the "*Completions*" buffer.
+++
-*** New option 'completions-header-format'
+*** New user option 'completions-header-format'
This is a string to control the message to show before completions.
-It may contain a "%s" to show the total number of completions. If nil no
+It may contain a "%s" to show the total number of completions. If nil no
completions are shown.
+++
-*** New option 'completions-highlight-face'.
-When this variable is a face name, it highlights the current candidate
-in the "*Completions*" buffer with that face. When the value is nil,
-no highlighting is performed at all.
+*** New user option 'completions-highlight-face'.
+When this user option is a face name, it highlights the current
+candidate in the "*Completions*" buffer with that face. When the
+value is nil, no highlighting is performed at all.
** Isearch and Replace
---
** The 'inhibit-changing-match-data' variable is now obsolete.
Instead, functions like 'string-match' and 'looking-at' now take an
-optional 'inhibit-modify' argument.
+optional INHIBIT-MODIFY argument.
---
** 'gnus-define-keys' is now obsolete.
** New 'cursor-face' text property.
This uses 'cursor-face' instead of the default face when cursor is on or
near the character and 'cursor-face-highlight-mode' is enabled. The
-variable 'cursor-face-highlight-nonselected-window' is similar to
+user option 'cursor-face-highlight-nonselected-window' is similar to
'highlight-nonselected-windows', but for this property.
+++
the clipboard, and insert it into the buffer.
---
-** New hook 'minibuffer-lazy-highlight-setup'.
-This hook is intended to be added to 'minibuffer-setup-hook'.
+** New function 'minibuffer-lazy-highlight-setup'.
+This function is intended to be added to 'minibuffer-setup-hook'.
It sets up the minibuffer for lazy highlighting of matches
in the original window.
---
** 'eshell-eval-using-options' now follows POSIX/GNU argument syntax conventions.
Built-in commands in Eshell now accept command-line options with
-values passed as a single token, such as '-oVALUE' or
-'--option=VALUE'.
+values passed as a single token, such as '-oVALUE' or '--option=VALUE'.
** XDG support
** 'indian-tml-base-table' no longer translates digits.
Use 'indian-tml-base-digits-table' if you want digits translation.
---
+---
** 'indian-tml-itrans-v5-hash' no longer translates digits.
Use 'indian-tml-itrans-digits-v5-hash' if you want digits
translation.
++++
+** 'shell-quote-argument' has a new optional parameter POSIX.
+This is useful when quoting shell arguments for a remote shell
+invocation. Such shells are POSIX conform by default.
+
\f
* Changes in Emacs 29.1 on Non-Free Operating Systems
,grep-use-null-filename-separator)
(grep-find-use-xargs ,grep-find-use-xargs)
(grep-highlight-matches ,grep-highlight-matches)))))
- (let* ((host-id
- (intern (or (file-remote-p default-directory) "localhost")))
+ (let* ((remote (file-remote-p default-directory))
+ (host-id (intern (or remote "localhost")))
(host-defaults (assq host-id grep-host-defaults-alist))
(defaults (assq nil grep-host-defaults-alist))
- (quot-braces (shell-quote-argument "{}"))
- (quot-scolon (shell-quote-argument ";")))
+ (quot-braces (shell-quote-argument "{}" remote))
+ (quot-scolon (shell-quote-argument ";" remote)))
;; There are different defaults on different hosts. They must be
;; computed for every host once.
(dolist (setting '(grep-command grep-template
(defun grep-default-command ()
"Compute the default grep command for \\[universal-argument] \\[grep] to offer."
- (let ((tag-default (shell-quote-argument (grep-tag-default)))
+ (let ((tag-default
+ (shell-quote-argument
+ (grep-tag-default) (file-remote-p default-directory)))
;; This a regexp to match single shell arguments.
;; Could someone please add comments explaining it?
(sh-arg-re
("<F>" . files)
("<N>" . (null-device))
("<X>" . excl)
- ("<R>" . (shell-quote-argument (or regexp ""))))
+ ("<R>" . (shell-quote-argument
+ (or regexp "") (file-remote-p (expand-file-name (or dir "."))))))
"List of substitutions performed by `grep-expand-template'.
If car of an element matches, the cdr is evalled in order to get the
substitution string.
(when (and (stringp regexp) (> (length regexp) 0))
(unless (and dir (file-accessible-directory-p dir))
(setq dir default-directory))
- (let ((command regexp))
+ (let ((command regexp) remote)
(if (null files)
(if (string= command grep-command)
(setq command nil))
- (setq dir (file-name-as-directory (expand-file-name dir)))
+ (setq dir (file-name-as-directory (expand-file-name dir))
+ remote (file-remote-p dir))
(unless (or (not grep-use-directories-skip)
(eq grep-use-directories-skip t))
(setq grep-use-directories-skip
(mapconcat
(lambda (ignore)
(cond ((stringp ignore)
- (shell-quote-argument ignore))
+ (shell-quote-argument
+ ignore remote))
((consp ignore)
(and (funcall (car ignore) dir)
(shell-quote-argument
- (cdr ignore))))))
+ (cdr ignore) remote)))))
grep-find-ignored-files
" --exclude=")))
(and (eq grep-use-directories-skip t)
(defun rgrep-default-command (regexp files dir)
"Compute the command for \\[rgrep] to use by default."
(require 'find-dired) ; for `find-name-arg'
- (grep-expand-template
- grep-find-template
- regexp
- (concat (shell-quote-argument "(")
- " " find-name-arg " "
- (mapconcat
- #'shell-quote-argument
- (split-string files)
- (concat " -o " find-name-arg " "))
- " "
- (shell-quote-argument ")"))
- dir
- (concat
- (and grep-find-ignored-directories
- (concat "-type d "
- (shell-quote-argument "(")
- ;; we should use shell-quote-argument here
- " -path "
- (mapconcat (lambda (d) (shell-quote-argument (concat "*/" d)))
- (rgrep-find-ignored-directories dir)
- " -o -path ")
- " "
- (shell-quote-argument ")")
- " -prune -o "))
- (and grep-find-ignored-files
- (concat (shell-quote-argument "!") " -type d "
- (shell-quote-argument "(")
- ;; we should use shell-quote-argument here
- " -name "
- (mapconcat
- (lambda (ignore)
- (cond ((stringp ignore)
- (shell-quote-argument ignore))
- ((consp ignore)
- (and (funcall (car ignore) dir)
- (shell-quote-argument
- (cdr ignore))))))
- grep-find-ignored-files
- " -o -name ")
- " "
- (shell-quote-argument ")")
- " -prune -o ")))))
+ (let ((remote (file-remote-p (or dir default-directory))))
+ (grep-expand-template
+ grep-find-template
+ regexp
+ (concat (shell-quote-argument "(" remote)
+ " " find-name-arg " "
+ (mapconcat
+ (lambda (x) (shell-quote-argument x remote))
+ (split-string files)
+ (concat " -o " find-name-arg " "))
+ " "
+ (shell-quote-argument ")" remote))
+ dir
+ (concat
+ (and grep-find-ignored-directories
+ (concat "-type d "
+ (shell-quote-argument "(" remote)
+ ;; we should use shell-quote-argument here
+ " -path "
+ (mapconcat
+ (lambda (d) (shell-quote-argument (concat "*/" d) remote))
+ (rgrep-find-ignored-directories dir)
+ " -o -path ")
+ " "
+ (shell-quote-argument ")" remote)
+ " -prune -o "))
+ (and grep-find-ignored-files
+ (concat (shell-quote-argument "!" remote) " -type d "
+ (shell-quote-argument "(" remote)
+ ;; we should use shell-quote-argument here
+ " -name "
+ (mapconcat
+ (lambda (ignore)
+ (cond ((stringp ignore)
+ (shell-quote-argument ignore remote))
+ ((consp ignore)
+ (and (funcall (car ignore) dir)
+ (shell-quote-argument
+ (cdr ignore) remote)))))
+ grep-find-ignored-files
+ " -o -name ")
+ " "
+ (shell-quote-argument ")" remote)
+ " -prune -o "))))))
(defun grep-find-toggle-abbreviation ()
"Toggle showing the hidden part of rgrep/lgrep/zrgrep command line."
(declare-function w32-shell-dos-semantics "w32-fns" nil)
-(defun shell-quote-argument (argument)
+(defun shell-quote-argument (argument &optional posix)
"Quote ARGUMENT for passing as argument to an inferior shell.
This function is designed to work with the syntax of your system's
standard shell, and might produce incorrect results with unusual shells.
-See Info node `(elisp)Security Considerations'."
- (cond
- ((eq system-type 'ms-dos)
+See Info node `(elisp)Security Considerations'.
+
+If the optional POSIX argument is non-nil, ARGUMENT is quoted
+according to POSIX shell quoting rules, regardless of the
+system's shell."
+(cond
+ ((and (not posix) (eq system-type 'ms-dos))
;; Quote using double quotes, but escape any existing quotes in
;; the argument with backslashes.
(let ((result "")
start (1+ end))))
(concat "\"" result (substring argument start) "\"")))
- ((and (eq system-type 'windows-nt) (w32-shell-dos-semantics))
+ ((and (not posix) (eq system-type 'windows-nt) (w32-shell-dos-semantics))
;; First, quote argument so that CommandLineToArgvW will
;; understand it. See