0

I have to pass a command with its arguments in a scheduled task, while separating the arguments from the command. I used:

split(/(?=\s-)/)

to do this, but it won't work when the argument is not passed as -arg format.

Example of commands can be passed in format:

"ping http://www.google.com" here url is argument
"abc-abc -V"
"abc-abc -L c:\\folder name\\test.log"
'"C:\\Program Files\\example\\program.exe" -arg1 -arg2'
"C:\\Program Files\\example\\program.exe"

To make this more clear these commands are not passed as command line argument which can get in ARGV

The command gets set in command property which accepts input in string format

command '"C:\\Program Files\\example\\program.exe" -arg1 -arg2'

vasu
  • 391
  • 3
  • 13
  • i think you should be looking for regular expression, the problem remaining is that your commands have many different syntaxes (command and args separated by space, but not for "C:\\Program Files" for example, then separated by '-' . Does it have to work with all syntaxes for your project ? – Alexis Delahaye May 15 '18 at 08:17
  • Can your command ever contain whitespace? If not, could you split on whitespace, treat the first token as the command and then format the arguments or options as appropriate? – rwold May 15 '18 at 08:51
  • @rwold spliting on whitespace will not work where command is like ```"C:\\Program Files\\example\\program.exe"``` – vasu May 15 '18 at 08:57
  • @AlexisDelahaye yes it should work with all examples – vasu May 15 '18 at 08:59
  • @vasu (1) Your example is not valid ruby syntax; I presume you meant `/(?=\s-)/`. (2) Why won't that example work by just splitting on space? Even in the comment above, I don't see how that will fail? (3) There's probably no need to "reinvent the wheel" here with some regex. There is a standard convention in almost all languages: The command line arguments are known as `ARGV`, which you can access in ruby as a constant. Ruby also provides [`ARGF`](https://ruby-doc.org/core/ARGF.html), which works as a data stream. – Tom Lord May 15 '18 at 09:36
  • @vasu If you need more complex/custom handling of command line arguments, the ruby standard library also provides [`OptionParser`](https://docs.ruby-lang.org/en/2.5.0/OptionParser.html), or for even more advanced usage there are several popular third party libraries such as [`thor`](https://github.com/erikhuda/thor). However you go about solving this (although I'm unsure what "this" actually is, given your vague problem description: *"it won't work"*), I doubt you need to reinvent any wheels. – Tom Lord May 15 '18 at 09:41
  • @vasu D'oh! My eyes glossed over that expecting Unix style escaping that would be easily fixed. See my answer. – rwold May 15 '18 at 09:42
  • @TomLord I have edited my question for ruby syntax and more details why can't it be get in ARGV. Answer to your question why it won't work for splitting on space is if command contains file path with File name like Program File it will split on space and will separate out the file name. – vasu May 15 '18 at 10:02
  • @vasu You still don't need to look beyond the ruby standard library, and certainly not use any weird regex like the other answers are suggesting. I'll post something below.... – Tom Lord May 15 '18 at 10:06

3 Answers3

3

Use Shellwords.split, from the standard library:

Shellwords.split("ping http:\\www.google.com here url is argument")
  #=> ["ping", "http:www.google.com", "here", "url", "is", "argument"]
Shellwords.split("abc-abc -V")
  #=> ["abc-abc", "-V"]
Shellwords.split("abc-abc -L c:\\folder name\\test.log")
  #=> ["abc-abc", "-L", "c:folder", "nametest.log"]
Shellwords.split('"C:\\Program Files\\example\\program.exe" -arg1 -arg2')
  #=> ["C:\\Program Files\\example\\program.exe", "-arg1", "-arg2"]
Shellwords.split('"C:\\Program Files\\example\\program.exe"')
  #=> ["C:\\Program Files\\example\\program.exe"]

No need to reinvent the wheel with a custom regex/splitter, or an external system call.

Tom Lord
  • 27,404
  • 4
  • 50
  • 77
  • I checked Shellwords and only worried where it takes on ```\\``` from file path here ```Shellwords.split("abc-abc -L c:\\folder name\\test.log") #=> ["abc-abc", "-L", "c:folder", "nametest.log"]``` – vasu May 15 '18 at 10:33
  • @vasu That's not a valid example. In order to pass a pathname with spaces like this, you would need to wrap it in quotes - i.e. `Shellwords.split("abc-abc -L 'c:\\folder name\\test.log'") #=> ["abc-abc", "-L", "c:\\folder name\\test.log"]` – Tom Lord May 15 '18 at 10:36
  • Are any of the examples I provided above different from the result you require? In which case, what result *do* you require? Are there other example inputs for which this won't work? What inputs? What result do you require? – Tom Lord May 15 '18 at 10:39
  • This case also removes ```\\``` here ```Shellwords.split("ping http:\\www.google.com here url is argument") #=> ["ping", "http:www.google.com", "here", "url", "is", "argument"]``` – vasu May 15 '18 at 10:42
  • @vasu Which website are you visiting with backslashes in the URL? :S Again, the's not a valid example - you would actually need to do `Shellwords.split("ping 'http:\\\\www.google.com' here url is argument")` (note the additional quotes, and double-backslash). But again, this feels very contrived since URIs don't contain backslashes! – Tom Lord May 15 '18 at 10:51
  • If anything, this use of `Shellwords.split` rather than a custom regex only helps illustrate my point: Your code should be parsing the string via standard libraries, to avoid buggy behaviour from false assumptions about dodgy input! – Tom Lord May 15 '18 at 10:52
  • My bad here about URI – vasu May 15 '18 at 10:54
0

Tom Lord's answer is far better than this one.


You probably want to look at OptionParser or GetOptLong if you need parsing of command line arguments provided to a ruby program.


If you are interested in parsing some strings that may or may not be commands with arguments, here's a quick-and-dirty:

I'd use scan instead of split with the following regex: /(".*"|[\w\:\:\.\-\\]+)/.

Best results come from: 'some string'.scan(/(".*"|[\w\:\:\.\-\\]+)/).flatten:

["ping", "http:\\www.google.com"]
["abc-abc", "-V"]
["abc-abc", "-L", "c:\\folder\\", "name\\test.log"]
# Technically, this is wrong, but so is the non-escaped whitespace.
["\"C:\\Program Files\\example\\program.exe\"", "-arg1", "-arg2"]
["\"C:\\Program Files\\example\\program.exe\""]
Maciej Szlosarczyk
  • 789
  • 2
  • 7
  • 21
0

It seems to me that if there's no consistent pattern to your command syntax, then any regex based approach will inevitably fail. It seems better instead to solve this problem the way a human would, i.e. with some knowledge of context.

In a *nix terminal, you can use the compgen command to list available commands. This Ruby script invokes that command to print the first 5 options from that list:

list = `cd ~ && compgen -c`
list_arr = list.split("\n")
list_arr[0,6].each{|x| puts x }

(The cd in the first line seems to be needed because of the context in which my Ruby is running with rvm.) For Windows, you may find this thread a useful starting point.

I'd match against the elements of this list to identify my commands, and take it from there.

rwold
  • 2,216
  • 1
  • 14
  • 22