Subject: Re: bug#10598: 24.0.92; run dired-do-async-shell-command on multiple files individually

From: Juri Linkov <[email-masked]>
Date: Thu, 12 Jul 2012 12:01:30 +0300

>> I think `dired-shell-stuff-it' should be improved to translate
>> `gv foo.ps&;gv bar.ps&' into `gv foo.ps&gv bar.ps&' or into
>> `gv foo.ps;gv bar.ps&' depending on whether you want to run
>> asynchronously both at the same time or sequentially
>> (perhaps a new option should define that).
>
> Good point! In my case I wanted to run the commands asynchronously
> at the same time. Others might want to run the command
> asynchronously, but sequentially.

This can be fixed with the following patch:

=== modified file 'lisp/dired-aux.el'
--- lisp/dired-aux.el	2012-04-17 01:52:00 +0000
+++ lisp/dired-aux.el	2012-07-12 08:51:48 +0000
@@ -542,12 +542,25 @@ (defun dired-read-shell-command (prompt
       (dired-mark-pop-up nil 'shell files
 			 'read-shell-command prompt nil nil))))
 
+(defvar dired-async-each t
+  "How to run `dired-do-async-shell-command' on multiple files individually.
+When non-nil, run asynchronous commands on each file parallelly.
+In shell syntax this means separating the individual commands with `&'.
+When nil, run commands in the background on each file sequentially
+waiting for each command to terminate before running the next command.
+In shell syntax this means separating the individual commands with `;'.")
+
 ;;;###autoload
 (defun dired-do-async-shell-command (command &optional arg file-list)
   "Run a shell command COMMAND on the marked files asynchronously.
 
-Like `dired-do-shell-command' but if COMMAND doesn't end in ampersand,
-adds `* &' surrounded by whitespace and executes the command asynchronously.
+Like `dired-do-shell-command' but adds `&' at the end of COMMAND
+to execute it asynchronously.
+
+When operating on multiple files, the variable `dired-async-each'
+defines whether to run asynchronous commands on each file parallelly
+or sequentially.
+
 The output appears in the buffer `*Async Shell Command*'."
   (interactive
    (let ((files (dired-get-marked-files t current-prefix-arg)))
@@ -556,14 +569,10 @@ (defun dired-do-async-shell-command (com
       (dired-read-shell-command "& on %s: " current-prefix-arg files)
       current-prefix-arg
       files)))
-  (unless (string-match "[*?][ \t]*\\'" command)
-    (setq command (concat command " *")))
   (unless (string-match "&[ \t]*\\'" command)
     (setq command (concat command " &")))
   (dired-do-shell-command command arg file-list))
 
-;; The in-background argument is only needed in Emacs 18 where
-;; shell-command doesn't understand an appended ampersand `&'.
 ;;;###autoload
 (defun dired-do-shell-command (command &optional arg file-list)
   "Run a shell command COMMAND on the marked files.
@@ -655,7 +661,11 @@ (defun dired-shell-stuff-it (command fil
 ;; Might be redefined for smarter things and could then use RAW-ARG
 ;; (coming from interactive P and currently ignored) to decide what to do.
 ;; Smart would be a way to access basename or extension of file names.
-  (let ((stuff-it
+  (let* ((in-background (string-match "[ \t]*&[ \t]*\\'" command))
+	 (command (if in-background
+		      (substring command 0 (match-beginning 0))
+		    command))
+	 (stuff-it
 	 (if (or (string-match dired-star-subst-regexp command)
 		 (string-match dired-quark-subst-regexp command))
 	     (lambda (x)
@@ -665,13 +675,16 @@ (defun dired-shell-stuff-it (command fil
 		   (setq retval (replace-match x t t retval 2)))
 		 retval))
 	   (lambda (x) (concat command dired-mark-separator x)))))
+    (concat
     (if on-each
-	(mapconcat stuff-it (mapcar 'shell-quote-argument file-list) ";")
+	 (mapconcat stuff-it (mapcar 'shell-quote-argument file-list)
+		    (if (and in-background dired-async-each) "&" ";"))
       (let ((files (mapconcat 'shell-quote-argument
 			      file-list dired-mark-separator)))
 	(if (> (length file-list) 1)
 	    (setq files (concat dired-mark-prefix files dired-mark-postfix)))
-	(funcall stuff-it files)))))
+	 (funcall stuff-it files)))
+     (if in-background "&" ""))))
 
 ;; This is an extra function so that it can be redefined by ange-ftp.
 ;;;###autoload