# Missing Execution

**URL:** <https://forum.crystal-lang.org/t/missing-execution/2172>\
**Category:** Help & Support\
**Created:** [May 26, 2020, 5:40am UTC](https://forum.crystal-lang.org/t/missing-execution/2172 "2020-05-26T05:40:28Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![glued2thefloor](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/glued2thefloor/32/839_2.png) [@glued2thefloor](https://forum.crystal-lang.org/u/glued2thefloor)\
**Post date:** [May 26, 2020, 5:40am UTC](https://forum.crystal-lang.org/t/missing-execution/2172/1 "2020-05-26T05:40:28Z")

</div>

Okay, there’s probably a lot of stuff in this code that can be improved, and I am willing to listen. The reason I’m here though is because this program in its current state doesn’t execute anything and I feel it should:

```
require "option_parser"

string = ""
passname = ""
things = ""
uname = ""
ip = ""

option_parser = OptionParser.parse do |parser|
  parser.banner = "Awesomeness 1.0"

  parser.on "-v", "--version", "Show version" do
    puts "version 1.0"
    exit
  end
  parser.on "-h", "--help", "Show help" do
    puts parser
    exit
  end
  parser.on "-d ENCRYPTED_FILE", "--dcrypt ENCRYPTED_FILE", "Decrypt and user encrypted file with ccrypt" do |dcrypt|
    dname = dcrypt
  end
  parser.on "-w PASSWORD", "--pass PASSWORD", "Password if SSH keys are not used" do |pass|
    passname = pass
  end 
  parser.on "-p PORT", "--port PORT", "Port for SSH if not default" do |port|
    pname = port
  end
  parser.on "-u USER", "--user USER", "Username" do |user|
    uname = user
  end
  parser.on "-l HOST", "--host HOST", "Host or IP" do |host|
    ip = host
  end  
  parser.on "-f FILENAME", "--file FILENAME", "File of hosts" do |file|
    hostfile = file
  end
  parser.on "-e COMMANDS", "--execute COMMANDS", "Commands to run" do |commands|
    things = commands
  end
end

if(passname.empty? != true)
  string = "sshpass -p \"#{passname}\" "
end

string += "ssh -o StrictHostChecking=no -T "

if(uname.empty? != true)
  string += "#{uname}@"
end

if(ip.empty? != true)
  string += "#{ip} "
end

if(things.empty? != true)
  string += "\"#{things}\""
end

unless things.empty?
  Process.run(string, shell: true) do |proc|
  IO.copy(proc.output, STDOUT)
 end
end

```

The reason I feel it “should” work, is that I see the output of the program display correctly when I run it through strace:

`[pid 164083] 18:40:24 execve("/usr/bin/sshpass", ["sshpass", "-p", "password", "ssh", "-o", "StrictHostChecking=no", "-T", "user@192.168.x.x", "date"], ["SHELL=/bin/bash", "COLORTERM=truecolor",...`

Program will need to be ran like this right now as I’ve added zero error checking so far.

`./program -u username -l 192.168.x.x -w "password" -e date`

I don’t see anything needing to be escaped in the strace output, but perhaps it needs more escaping? Any advice appreciated.

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [May 26, 2020, 6:04am UTC](https://forum.crystal-lang.org/t/missing-execution/2172/2 "2020-05-26T06:04:11Z")

</div>

Some tips:

1. String should be the process you’re executing, like `ssh` in this example.
2. You should use an array of strings to hold the arguments. I.e the second argument to [Process.run](https://crystal-lang.org/api/master/Process.html#run(command:String,args=nil,env:Env=nil,clear_env:Bool=false,shell:Bool=false,input:Stdio=Redirect::Close,output:Stdio=Redirect::Close,error:Stdio=Redirect::Close,chdir:String?=nil):Process::Status-class-method).
3. You can just set the output of `Process.run` to be `STDOUT`.
4. You can just do like `string += "#{uname}@" unless uname.empty?` (but using an array). No need for `uname.empty? != true` .

Some sample code:

```auto
command = "ssh"
args = ["-o", "StrictHostChecking=no", "-T"]

args.push "sshpass", "-p", passname unless passname.empty?

result = Process.run command, args, output: STDOUT

```

I’m not sure if this’ll solve your issue or not, but should at least make it a bit cleaner and easier to figure out.

---

<div class="post-metadata">

**Author:** ![HankAnderson](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/hankanderson/32/834_2.png) [@HankAnderson](https://forum.crystal-lang.org/u/HankAnderson)\
**Post date:** [May 26, 2020, 11:53am UTC](https://forum.crystal-lang.org/t/missing-execution/2172/3 "2020-05-26T11:53:18Z")

</div>

@Blacksmoke16 With `shell: true` you can pass the command and all arguments in the first argument. So points 1 and 2 of what you said don’t apply in this case.

---

<div class="post-metadata">

**Author:** ![ducktape](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ducktape/32/846_2.png) [@ducktape](https://forum.crystal-lang.org/u/ducktape)\
**Post date:** [May 26, 2020, 10:58pm UTC](https://forum.crystal-lang.org/t/missing-execution/2172/4 "2020-05-26T22:58:11Z")

</div>

@glued2thefloor, unrelated to your problem, but you may be interested in the 'Percent string literals` [https://crystal-lang.org/reference/syntax\_and\_semantics/literals/string.html](https://crystal-lang.org/reference/syntax_and_semantics/literals/string.html) that would allow you to not have to escape quotes:

```auto
things = "cats"
"\"#{things}\"" == %<"#{things}"> 

```

[https://play.crystal-lang.org/#/r/95hj](https://play.crystal-lang.org/#/r/95hj)

Also, I believe `system` command automatically inherits stderr and stdout from your current process.  
[https://crystal-lang.org/api/0.34.0/toplevel.html#system(command:String,args=nil):Bool-class-method](https://crystal-lang.org/api/0.34.0/toplevel.html#system(command:String,args=nil):Bool-class-method)

---

<div class="post-metadata">

**Author:** ![glued2thefloor](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/glued2thefloor/32/839_2.png) [@glued2thefloor](https://forum.crystal-lang.org/u/glued2thefloor)\
**Post date:** [May 27, 2020, 7:39am UTC](https://forum.crystal-lang.org/t/missing-execution/2172/5 "2020-05-27T07:39:19Z")

</div>

@HankAnderson - Thank you. I was thinking `shell: true` was required. As I’m new to Crystal I wasn’t 100% positive though.

@Blacksmoke16 - For point #4, I should have stated this, but I’m trying to port some code from another project I did in C. Some of those can be fixed like you said, but some will have error checking added later. Obviously someone can’t ssh somewhere with no host specified. I was going to print out an error message later if the some of the results were null and figured an if statement would be the best way to do this. Maybe I’m wrong though. I did like the way you used unless here. Also, I did try your suggestion with STDOUT:

require “option\_parser”

```
passname = ""
things = ""
uname = ""
ip = ""

option_parser = OptionParser.parse do |parser|
  parser.banner = "Awesomeness 1.0"

  parser.on "-v", "--version", "Show version" do
    puts "version 1.0"
    exit
  end
  parser.on "-h", "--help", "Show help" do
    puts parser
    exit
  end
  parser.on "-d ENCRYPTED_FILE", "--dcrypt ENCRYPTED_FILE", "Decrypt and user encrypted file with ccrypt" do |dcrypt|
    dname = dcrypt
  end
  parser.on "-w PASSWORD", "--pass PASSWORD", "Password if SSH keys are not used" do |pass|
    passname = pass
  end 
  parser.on "-p PORT", "--port PORT", "Port for SSH if not default" do |port|
    pname = port
  end
  parser.on "-u USER", "--user USER", "Username" do |user|
    uname = user
  end
  parser.on "-l HOST", "--host HOST", "Host or IP" do |host|
    ip = host
  end  
  parser.on "-f FILENAME", "--file FILENAME", "File of hosts" do |file|
    hostfile = file
  end
  parser.on "-e COMMANDS", "--execute COMMANDS", "Commands to run" do |commands|
    things = commands
  end
end

command = "ssh"
args = ["-o", "StrictHostChecking=no", "-T", "user@192.168.x.x", "date"]
args.push "sshpass", "-p", passname unless passname.empty?
result = Process.run command, args, output: STDOUT

```

I then ran it like so:  
`./program -w "password"`  
but received no output.

Looking at this in strace again it seems the commands to be executed were out of order:  
`[pid 278978] 02:24:30 execve("/usr/bin/ssh", ["/usr/bin/ssh", "-o", "StrictHostChecking=no", "-T", "ph33r@192.168.x.x", "date", "sshpass", "-p", "password"], ["SHELL=/bin/bash", "COLORTERM=truecolor"...`

Any thoughts?

@ducktape - Thank you. I will look into this later. Good find.

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [May 27, 2020, 12:50pm UTC](https://forum.crystal-lang.org/t/missing-execution/2172/6 "2020-05-27T12:50:20Z")

</div>

> [@glued2thefloor](#):
>
> I then ran it like so:  
> `./program -w "password"`  
> but received no output.

Try also outputting errors, add a `, error: STDERR` to the `Process.run`. As currently any errors would be silenced.

---

<div class="post-metadata">

**Author:** ![glued2thefloor](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/glued2thefloor/32/839_2.png) [@glued2thefloor](https://forum.crystal-lang.org/u/glued2thefloor)\
**Post date:** [May 28, 2020, 10:29pm UTC](https://forum.crystal-lang.org/t/missing-execution/2172/7 "2020-05-28T22:29:03Z")

</div>

Well, not sure if I’m doing this right, but I just changed the last lines of the program to this:

```
command = "ssh"
args = ["-o", "StrictHostChecking=no", "-T", "user@192.168.x.x", "date"]
args.push "sshpass", "-p", passname unless passname.empty?
result = Process.run command, args, output: STDERR

```

I executed this again with the password and got no output again. Maybe I put STDERR in the wrong place?

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [May 28, 2020, 10:41pm UTC](https://forum.crystal-lang.org/t/missing-execution/2172/8 "2020-05-28T22:41:01Z")

</div>

Now you’ve set `STDOUT` to `STDERR`. You want to do `result = Process.run command, args, output: STDOUT, error: STDERR`. So that normal output goes to `STDOUT` and error output goes to `STDERR`. I’m pretty sure these should be the default tho… I don’t remember.

---

<div class="post-metadata">

**Author:** ![jhass](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jhass/32/1779_2.png) [@jhass](https://forum.crystal-lang.org/u/jhass)\
**Post date:** [May 29, 2020, 7:57am UTC](https://forum.crystal-lang.org/t/missing-execution/2172/9 "2020-05-29T07:57:42Z")

</div>

Default behavior is `:close`. You can use `output: :inherit` etc. instead of having to do it explicitly.
