Difference in behaviour between Cygwin and Command Prompt when running Ruby scripts - ruby

I'm running exercise 14 of Learn Ruby the Hard Way. If I run the script in cmd it works fine, but I've been using Cygwin because it's nicer. When I run it in cygwin using this command:
ruby ex14.rb Devon
I get the following output
test
one
two
Hi Devon, I'm the ex14.rb script.
I'd like to ask you a few questions.
Do you like me Devon?
> Where do you live Devon?
> What kind of computer do you have?
> Alright, so you said test about liking me.
You live in one. Not sure where that is.
And you have a two computer. Nice.
That is to say, the program starts and immediately runs the three STDIN.gets.chomp() commands, and once it gets through those it puts and prints everything at once.
Is there a way to fix this behaviour? I would obviously want to have the lines run in the order they are written. I was unsure what to google for this type of error - combinations of "cygwin", "ruby", "puts output delayed" and "gets out of order" returned nothing relevant. Those search terms seem to vague anyway.
What exactly is going on, and is there a solution?

I think it is all to do with the CR LF differences between dos and unix.
try this...
set -o igncr
before running your script.

Related

Is it possible to make a .bat Bash hybrid?

In cmd, it is possible to use Linux commands with the ubuntu or bash commands, but they are very fickle. In batch, it is also possible to make a VBScript-batch hybrid, which got me thinking, is it possible to make a Bash-batch hybrid? Besides being a tongue-twister, I feel that Bash-batch scripts may be really useful.
What I have tried so far
So far I tried using the empty bash and ubuntu commands alone since they switch the normal command-prompt to the Ubuntu/Bash shell, but even if you put commands after the ubuntu/bash they wouldn't show or do anything.
After I tried that, I tried using the ubuntu -run command, but like I said earlier, it’s really fickle and inconsistent on what things work and what things don't. It is less inconsistent when you pipe things into it, but it still usually doesn't work.
I looked here since it seemed like it would answer my question and I tried it, but it didn't work since it required another program (I think).
I also looked to this and I guess it failed miserably, but interesting concept.
What I've gotten from all of my research is that most people think when this is mentioned of a file that could be run either as a .bat file or as .sh shell file instead of my goal, to make a file that runs both batch and Bash commands in the same instance.
What I want this for relates to my other question where I am trying to hash a string instead of a file in cmd, and you could do it with a Bash command, but I would still like to keep the file as a batch file.
Sure you can use Bash in batch, assuming it is available. Just use the command bash -c 'cmd', where cmd is the command that you want to run in Bash.
The following batch line pipes the Hello to cat -A command that prints it including the invisible symbols:
echo Hello | bash -c "cat -A"
Compare the output with the result of the version completely written in Bash:
bash -c "echo Hello | cat -A"
They will slightly differ!

Get results of command from Cygwin in Batch

The Problem
I'm a little new to Cygwin and I'm trying to run a shell script in Cygwin from Batch and get the return value. I've been searching around, and I tried using C:\cygwin[64]\bin\bash[64].exe and even messing with C:\cygwin[64]\Cygwin.bat but to no avail.
Basically, I just want to be able to, from batch, interact with bash (from Cygwin). Please excuse me if this seems trivial to you, as I am rather new to Cygwin. Anyways, I have yet to find a working online solution.
Example Sudo Code:
cygwin-magic "echo shell-command"
#=> shell-command
Some Stuff I've Tried
I found all of these things from a lengthy Google hunt. Nothing did what I wanted it to.
"C:\cygwin[64]\bin\base[64].exe" /cygdrive/c/users/<me>/desktop/tmp.sh
#=> ZWNobyAiaGVsbG8i
"C:\cygwin[64]\bin\base[64].exe" -d /cygdrive/c/users/<me>/desktop/tmp.sh
#=> y▒h/usr/bin/base[64]: invalid input
"C:\cygwin[64]\bin\base[64].exe" -d -i /cygdrive/c/users/<me>/desktop/tmp.sh
#=> y▒h▒▒e/usr/bin/base[64]: invalid input
"C:\cygwin[64]\bin\base[64].exe" -d -i "echo hello"
#=> /usr/bin/base[64]: echo hello: No such file or directory
# I kind of gave up on all of my other attempts and tried this because why not? Surprise surprise, it didn't work (not that I expected it to).
"C:\cygwin[64]\Cygwin.bat"
echo "hello"
Contents of tmp.sh
Simply,
echo "hello"
Purpose
The reason I want to do this from batch is that I want to interact with bash from another language through batch (on Windows). I've got my solution planned out in that third language, but it's just the batch-to-cygwin that's not working.
Notes
Windows 7 Home Premium x64
Cygwin x64
I wrote all 64s in the code as [64] because I know 32-bit builds don't use that.
If I missed something or my question's a little off (too broad, too specific, etc.), please comment and I'll change it.
Perhaps you meant "C:\cygwin[64]\bin\basH[64].exe" not "C:\cygwin[64]\bin\base[64].exe"

what is the use of "#!/usr/local/bin/ruby -w" at the start of a ruby program

what is the use of writing the following command at the start of a ruby program ?
#!/usr/local/bin/ruby -w
Is it OS specific command? Is it valid for ruby on windows ? if not, then what is an equivalent command in windows ?
It is called a Shebang. It tells the program loader what command to use to execute the file. So when you run ./myscript.rb, it actually translates to /usr/local/bin/ruby -w ./myscript.rb.
Windows uses file associations for the same purpose; the shebang line has no effect (edit: see FMc's answer) but causes no harm either.
A portable way (working, say, under Cygwin and RVM) would be:
#!/usr/bin/env ruby
This will use the env command to figure out where the Ruby interpreter is, and run it.
Edit: apparently, precisely Cygwin will misbehave with /usr/bin/env ruby -w and try to look up ruby -w instead of ruby. You might want to put the effect of -w into the script itself.
The Shebang line is optional, and if you run the ruby interpreter and pass the script to it as a command line argument, then the flags you set on the command line are the flags ruby runs with.
A Shebang line is not ruby at all (unless you want to call it a ruby comment). It's really shell scripting. Most linux and unix users are running the BASH shell (stands for Borne Again SHell), but pretty much every OS has a command interpreter that will honor the Shebang.
“#!/usr/local/bin/ruby -w”
The "she" part is the octothorp (#), aka pound sign, number sign, hash mark, and now hash tag (I still call it tic-tac-toe just cuz).
The "bang" part is the exclaimation mark (!), and it's like banging your fist on the table to exclaim the command.
On Windows, the "Shell" is the command prompt, but even without a black DOS window, the command interpreter will run the script based on file associations. It doesn't really matter if the command interpreter or the programming langue is reading the shebang and making sure the flags are honored, the important point is, they are honored.
The "-w" is a flag. Basically it's an instruction for ruby to follow when it runs the script. In this case "-w" turns on warnings, so you'll get extra warnings (script keeps running) or errors (script stops running) during the execution of the script. Warnings and exceptions can be caught and acted upon during the program. These help programmers find problems that lead to unexpected behavior.
I'm a fan of quick and dirty scripts to get a job done, so no -w. I'm also a fan of high quality reusable coding, so definitely use -w. The right tool for the right job. If you're learning, then always use -w. When you know what you're doing, and stop using -w on quick tasks, you'll start to figure out when it would have helped to use -w instead of spending hours trouble shooting. (Hint, when the cause of a problem isn't pretty obvious, just add -w and run it to see what you get).
"-w" requires some extra coding to make it clear to ruby what you mean, so it doesn't immediately solve things, but if you already write code with -w, then you won't have much trouble adding the necessary bits to make a small script run with warnings. In fact, if you're used to using -w, you're probably already writing code that way and -w won't change anything unless you've forgotten something. Ruby requires far less "plumbing code" then most (maybe all) compiled languages like C++, so choosing to not use -w doesn't allow you to save much typing, it just lets you think less before you try running the script (IMHO).
-v is verbose mode, and does NOT change the running of the script (no warnings are raised, no stopping the script in new places). Several sites and discussions call -w verbose mode, but -w is warning mode and it changes the execution of the script.
Although the execution behavior of a shebang line does not translate directly to the Windows world, the flags included on that line (for example the -w in your question) do affect the running Ruby script.
Example 1 on a Windows machine:
#!/usr/local/bin/ruby -w
puts $VERBOSE # true
Example 2 on a Windows machine:
#!/usr/local/bin/ruby
puts $VERBOSE # false

why tcl expect exit unexpectly?

On Windows, I tested a tcl expect script as followed:
package require Expect
spawn "cmd.exe"
expect ">"
send "echo hello world\r"
But the output printed "F:\Workspace\>", then it exited.
Of cource, I expect that it executes "echo hello world"
Due to the way Expect for Windows works (it uses a special debugging mode) there are certain programs which can't be captured; telnet.exe is one, and cmd.exe could well be another. (The executables concerned have the system bit set in their file flags IIRC.)
Fortunately, the programs that this causes problems for are usually the ones that you don't actually need to automate with Expect. Tcl is quite capable of talking to other machines directly (by opening a socket) and cmd is both often unneeded and (in the other cases) easy to automate by just using the exec command. If this was just a test that was a proxy for your real automation, don't worry too much for now; try to automate the real program, though just do something simple (like exit cleanly) to start out with and build up from there.
It might be better if you tell me the problem you're really trying to solve. But anyway, you just need to type
echo hello world
instead of
send "echo hello world\r"
to get the result you require.
cheers
Brian

powershell script exits in "if" clause if run from command prompt

I am feeling surprised by the difference between two seemingly identical scripts.
first.ps1:
"A"
if ($true) { "B" }
"C"
second.ps1:
"A"
if ($true) { "B"
}
"C"
Now open a CMD window, and run these scripts like this:
powershell - < first.ps1
powershell - < second.ps1
first produces:
A
B
C
while second produces just
A
This has to be a bug.
In the redirection under cmd.exe case, the function completes normally and correctly if the if and else blocks are individually all on one line:
$candidate = '.\foo.txt'
$current= '.\bar.txt'
"Comparison starts"
if ($(diff $(get-content $current) $(get-content $candidate)).length -gt 0){"There was a difference"}
else {"There was not a difference"}
"Comparison over"
But if either block is split up onto more than one line and that branch is taken, the script aborts with no warning/output.
I'd report this on the PowerShell feedback site (connect.microsoft.com).
Not sure why the redirection to input doesn't work, but if you just specify the script as an input argument to powershell, it seems to work:
C:\fa2>powershell.exe C:\fa2\tc.ps1
Comparison starts
There was a difference
Comparison over
Edit:
Yep, Jay proved it. The root problem is that Powershell does not support the '<' operator. I've been searching all day for some official documentaion on the web, but have not found it. I just occured to me to check some old notes, and I found a reference to this not being supported in v1. It only supports '>'.
I'll try to update if I find something more official than my memory. Leaving original text just for completnes.
I dont think the accepted answer is enitrely true here.
Take a look at Lee Holmes blog: link
He is one of the devs on the Powershell team, and wrote the Powershell Cookbook, just to give a little credence to his words.
I've run into this kind of problem with some complicated and archaic Bat scripts that relied on some funky fancy binary redirection. Powershell would run the Bat file, but at the point where the binary redirection took place it would just stop. Using [Process]:Start as described in the blog post worked wonderfully, and allowed me to parse the output of the Bat file like any other nicely behaved script to boot.
In your case I assume "diff" is an actuall exe and not a function, and its outputing binary and not text.
On a side note, I really don't see the need for redirecting the output of the script to Powershell like youre doing. Seems kind of counterproductive. You wrote a powershell script, seems like a waste not to use the paramter specifically provided to handle running input.
I don't think this is a bug. Try typing each of those lines in on the console and you will see what is happening. When you type and open bracket and don't close it, PowerShell goes into a multiline entering mode. To exit this mode, you need a closing bracket AND a blank line afterward. If you have a blank line before or after the "C" it should work.
Of course, maybe it is a bug and just has the same effect as multiline input. :)
I can't get this to work myself, powershell is ignoring what I send into it.

Resources