I have an issue with the perl (v5.26.3) commands system or exec (both have the same behaviour)
Both command work fine
system ('git','pull','-ff','--no-rebase');
system ('git submodule --quiet foreach --recursive "echo \${name}"');
But when I split the "git submodule" into the arguments:
system ('git','submodule','--quiet foreach','--recursive "echo \${name}"');
Perl returns:
usage: git submodule [--quiet] [--cached]
or: git submodule [--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
or: git submodule [--quiet] status [--cached] [--recursive] [--] [<path>...]
or: git submodule [--quiet] init [--] [<path>...]
or: git submodule [--quiet] deinit [-f|--force] (--all| [--] <path>...)
or: git submodule [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] [--] [<path>...]
or: git submodule [--quiet] set-branch (--default|--branch <branch>) [--] <path>
or: git submodule [--quiet] set-url [--] <path> <newurl>
or: git submodule [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
or: git submodule [--quiet] foreach [--recursive] <command>
or: git submodule [--quiet] sync [--recursive] [--] [<path>...]
or: git submodule [--quiet] absorbgitdirs [--] [<path>...]
How can I pass the arguments?
For the system invocation that takes a list we need to pass it the command broken into words
If there is more than one argument in LIST, or if LIST is an array with more than one value, starts the program given by the first element of the list with arguments given by the rest of the list. If there is only one scalar argument, the argument is checked for shell metacharacters, and if there are any, the entire argument is passed to the system's command shell for parsing (this is
/bin/sh -c
on Unix platforms, but varies on other platforms). If there are no shell metacharacters in the argument, it is split into words and passed directly toexecvp
, ...
(my emphasis) †
Let's look at a trivial example. Take a command like
ls -l --sort size dir "dir A"
and break it up, so to pass a list of "arguments" to the "command." There is no command ls -l
but there is ls
and its argument -l
. There is also no argument --sort size
; there is --sort
argument, and (its value) size
. But stuff protected by quotes, like "dir A"
, need be passed as such, as one "token." So: ('ls', '-l', '--sort', 'size', 'dir', 'dir A')
Same with '--quiet foreach'
-- what argument is that, says git
?
So, not knowing that git
command, I'd go with
system('git', 'submodule', '--quiet', 'foreach', '--recursive', '"echo \${name}"');
I am leaving that "echo \${name}"
exactly as it is since I don't know what it means. But that may well need be written differently, please clarify.‡
† See man 3 exec
.
But it is also instructive, and perhaps more easily understood, to see how the shell (bash) does this, once it parses a line given to it. It is the "Step 6" on the linked wiki page, where the command is finally prepared to be passed to the program.
‡ Coming to think about it -- thanks to ikegami
for a comment -- it is unclear, while it sure matters, what that presumed $name
variable is and ... who it belongs to. Does it need to be extrapolated at some stage, or is it a git
thing that need be passed to git
as is?
This does not affect the overall point of this answer: to break the command into words to pass to system
's invocation with LIST. That means essentially to break it by space, except for parts where space is escaped (like it effectively is by quotes).
(Also see the exec page, at least for how to use LIST invocation in a case when there's only one argument but we still want to avoid the shell.)