Fix grep-like functions when running on a remote host

* doc/lispref/processes.texi (Shell Arguments):
* etc/NEWS: Describe change in 'shell-quote-argument'.  Fix typos.

* lisp/subr.el (shell-quote-argument): New optional argument POSIX.

* lisp/progmodes/grep.el (grep-compute-defaults)
(grep-default-command, grep-expand-keywords, lgrep)
(rgrep-default-command): Use POSIX argument in
`shell-quote-argument'.  (Bug#54487)
This commit is contained in:
Michael Albinus 2022-03-22 10:29:16 +01:00
parent 7872d496d5
commit 0094dde11d
4 changed files with 97 additions and 73 deletions

View file

@ -197,7 +197,7 @@ gives special treatment to certain characters, and if these characters
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
@ -227,6 +227,15 @@ 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
systems 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

View file

@ -578,9 +578,9 @@ the "*Completions*" buffer. Available styles are no sorting,
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
@ -591,16 +591,16 @@ some completion is made.
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
@ -1207,7 +1207,7 @@ like:
---
** 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.
@ -1330,7 +1330,7 @@ This allows setting a minimum display width for a region of text.
** 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.
+++
@ -1470,8 +1470,8 @@ This command lets you examine all data in the current selection and
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.
@ -1542,8 +1542,7 @@ from a specified amount of pixels above or below a position.
---
** '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
@ -1748,11 +1747,16 @@ This is recorded in the `function-history` symbol property.
** '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.
* Changes in Emacs 29.1 on Non-Free Operating Systems

View file

@ -632,12 +632,12 @@ The value depends on `grep-command', `grep-template',
,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
@ -820,7 +820,9 @@ The value depends on `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
@ -963,7 +965,8 @@ easily repeat a find command."
("<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.
@ -1112,11 +1115,12 @@ command before it's run."
(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
@ -1134,11 +1138,12 @@ command before it's run."
(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)
@ -1242,48 +1247,50 @@ command before it's run."
(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."

View file

@ -3760,14 +3760,18 @@ Note: :data and :device are currently not supported on Windows."
(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 "")
@ -3782,7 +3786,7 @@ See Info node `(elisp)Security Considerations'."
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