在REPL中执行以下命令:
(shell/sh "ls" "-lah" "'resources'")
给出以下输出:
{:exit 2, :out "", :err "ls: cannot access 'resources': No such file or directory\n"}
在Bash shell中执行相同的命令会提供正确的输出,即resources目录中的文件列表。据我所知,这意味着shell / sh无法正确处理单引号参数。这是真的还是我做错了什么?
上面的示例是一个简单的示例,因为通常我可能不需要单引号文件夹名称。但为什么这是一个真正的问题是因为我尝试通过使用shell / sh执行以下ffmpeg命令来连接音频文件;
ffmpeg -i resources/ffmpeg_working/1.flac
-i resources/ffmpeg_working/2.flac
-i resources/ffmpeg_working/3.flac
-i resources/ffmpeg_working/4.flac
-filter_complex '[0:0][1:0][2:0][3:0]concat=n=4:v=0:a=1[out]'
-map '[out]'
resources/ffmpeg_working/done.flac
这给出了以下输出
Stream map ''[out]'' matches no streams.
再一次,如果我在Bash shell中执行相同的ffmpeg命令,它会成功连接文件。因此,似乎单引号参数没有正确处理?
答案 0 :(得分:5)
引用是一个shell特性,以避免shell扩展,否则将被解释为通配符,变量等。当你使用shell以外的东西时,例如clojure / java进程管理工具,没有这样的东西作为通配符或变量,因此没有引用。
答案 1 :(得分:3)
正如提到的合金,您不应该在resources
周围使用单引号。与&比较无:
(require '[clojure.java.shell :as shell])
;=> nil
(shell/sh "ls" "-lah" "'resources'")
;=> {:exit 2, :out "", :err "ls: cannot access 'resources': No such file or directory\n"}
(shell/sh "ls" "-lah" "resources")
;=> {:exit 0, :out "total 8.0K\ndrwxrwxr-x 2 alan alan 4.0K Nov 4 2015 .\ndrwxrwxr-x 8 alan alan 4.0K Jul 14 10:25 ..\n", :err ""}
请注意,您根本没有运行任何外壳;你正在直接谈论unix内核,所以不会发生通配符扩展。例如,以下命令查找名为*
(星号)的文件,没有shell将*
字符解释为代表“任何匹配文件”的代码:
(shell/sh "ls" "-l" "*")
;=> {:exit 2, :out "", :err "ls: cannot access *: No such file or directory\n"}
如果您希望在传递给Linux内核之前让shell解释您的命令,您可能希望使用shell-cmd
函数in the Tupelo library:
(require '[tupelo.misc :as tm])
nil
clj.core=> (tm/shell-cmd "ls -l *")
{:exit 0, :out "-rw-rw-r-- 1 alan alan 11218 Nov 4 2015 LICENSE\n-rw-rw-r-- 1 alan alan 16 Jul 12 17:59 my-file.txt\n-rw-rw-r-- 1 alan alan 520 Jan 25 08:29 project.clj\n-rw-rw-r-- 1 alan alan 457 Nov 4 2015 README.md\n-rw-rw-r-- 1 alan alan 4975 Nov 4 2015 tmp.txt\n\ncheckouts:\ntotal 0\nlrwxrwxrwx 1 alan alan 17 Dec 7 2015 tupelo -> /home/alan/tupelo\n\ndoc:\ntotal 4\n-rw-rw-r-- 1 alan alan 101 Nov 4 2015 intro.md\n\nresources:\ntotal 0\n\nsrc:\ntotal 4\ndrwxrwxr-x 2 alan alan 4096 Feb 4 16:28 clj\n\ntarget:\ntotal 4\ndrwxrwxr-x 4 alan alan 4096 Jul 14 10:25 base+system+user+dev\n\ntest:\ntotal 4\ndrwxrwxr-x 3 alan alan 4096 Dec 7 2015 tst\n", :err ""}
请注意,shell-cmd
只接受一个直接传递给shell的字符串参数,而不是像clojure.java.shell/sh
这样的多个参数。
答案 2 :(得分:0)
如果需要外壳功能,可以直接调用外壳。 Bash支持-c
在正常的bash上下文中运行某些命令。当您需要从~/.profile
或~/.bashrc
进行设置时,这很有用。
(require '[clojure.java.shell :as shell])
(defn bash [command]
(shell/sh "bash" "-c"
command))
(bash "ls -lah 'resources'")
;; => {:exit 0, :out "lots of text", :err ""}
您现在可以使用任何Shell功能。管道示例:
(bash "find . | grep .clj")
;; => {:exit 0, :out "./src/user.clj\n", :err ""}
您的shell只是可以启动其他应用程序的应用程序。您可以告诉Shell启动应用程序。当您使用clojure.java.shell/sh启动应用程序时,您不是在bash之上执行 ,而是以bash启动其应用程序的方式。
不通过bash间接访问的优势: