RubyGems + Cygwin: POSIX path not found by ruby.exe - ruby

I am a Ruby programmer on Windows who trys to switch from Win cmd to Cygwin, but cannot achieve to execute batch files of Ruby gems.
I already stuffed any bin directory into the Windows PATH env. variable, including the Ruby bin where the executables are stored. Gems, however, are invoked by ruby.exe itself, which leads to the following problem with POSIX paths:
duddle#duddledan /cygdrive/c/Ruby/ruby-186-398/bin
$ gem -v
C:\Ruby\ruby-186-398\bin\ruby.exe: No such file or directory -- /cygdrive/c/Ruby/ruby-186-398/bin/gem (LoadError)
duddle#duddledan /cygdrive/c/Ruby/ruby-186-398/bin
$ ./gem --version
1.3.7
When calling e.g. ./gem directly by specifying the path, it can be found and executed.
Any ideas?
Edit:
How to tell cygwin not to process batch files?

You can mix and match Cygwin with MingW32 Ruby if you are careful and there are good reasons for doing so. Cygwin provides a more fleshed out CLI environment than does MSYS but Cygwin's bundled Ruby is much slower than the MingW32 version. The trick is to alias all the RubyGem wrappers in your Cygwin .bashrc. Here is a snippet from mine.
alias gem='gem.bat'
alias rake='rake.bat'
alias erb='erb.bat'
alias irb='irb.bat'
alias rdoc='rdoc.bat'
alias ri='ri.bat'
alias rspec='rspec.bat'
alias cucumber='cucumber.bat'
alias bundle='bundle.bat'

The trick is to alias all .bat files as Robert pointed out in his answer.
Adding a new alias to your .bashrc or .zshrc after every gem install ain't fun though ...
Therefore i create these aliases automatically by scanning Ruby's bindir:
if [[ -n "$(which ruby 2>/dev/null)" ]]; then
RUBY_BIN=$(cygpath -u $(ruby -e 'puts RbConfig::CONFIG["bindir"]') | tr '\r' ' ')
for f in $(find ${RUBY_BIN} -regex ".*bat$"| xargs -n1 basename); do
alias ${f%.bat}=${f}
done
fi

You're trying to mix batch files which expect native paths with Cygwin, which completely dislike it.
When you call ./gem you're invoking the ruby script, but using the PATH is invoking the batch file.
Either you tell cygwin not to process batch files (dunno how) or you use MSYS Bash if you want a replacement of cmd.exe, but don't mix Cygwin with native Ruby.
I've blogged about mixing and matching in the past:
http://blog.mmediasys.com/2008/10/27/handy-tip-dont-mix-one-click-installer-with-cygwin/

Related

How do you set an alias in zsh on Mac OS

I've set a zsh alias like this:
alias sed="/usr/local/Cellar/gnu-sed/4.8/bin/gsed"
I can confirm it is working by running:
type sed
sed is an alias for /usr/local/Cellar/gnu-sed/4.8/bin/gsed
However, if I put exactly the same code, alias setting and type sed then in a script under the file name test and run it get the default sed:
zsh test
sed is /usr/bin/sed
I've also tried it with extending PATH and still get the same thing which puzzles me...
The only thing that worked for me was to create a function. After that sed was overriden with gsed when I called the help argument
#!/bin/bash
sed () {
/usr/local/Cellar/gnu-sed/4.8/bin/gsed "$#"
}
sed --help
If you want to use the command word sed as gsed in all your future scripts (which if you really want to do, you can do this), Homebrew has info on how to achieve this, at the end of the installation for brew install gsed:
GNU "sed" has been installed as "gsed".
If you need to use it as "sed", you can add a "gnubin" directory
to your PATH from your bashrc like:
PATH="/opt/homebrew/opt/gnu-sed/libexec/gnubin:$PATH"
Though you are asking about zsh so I'm assuming you've upgraded to at least macOS Catalina and are now trying to use zsh instead of bash, so that means I would suggest putting the suggested line from Homebrew into ~/.zshrc instead of ~/.bashrc.
Some things have changed, the default Homebrew installation directory is now, well you can use the command brew --prefix to get your directory, it's now currently /opt/homebrew instead of the old /usr/local/Cellar.
Now your sed should run as gsed in all your scripts.
Additional notes
Reasons why your code involving aliases isn't working as expected and some additional notes to take away (speaking to zsh and bash):
Aliases in a script file disappear after the script has been run (unless the script is called by another script, then the calling script has the new alias definition).
Aliases executed in startup files like "~/.zshrc" etc. aren't used within script files.

How to make a Ruby file (in a gem) executable from anywhere like a regular command?

I have a command in my gem: bin/tennis. Currently to execute it you have to cd into the gem and run bin/tennis. I was wondering is it possible to make it work like a regular shell command? i.e able to run it from any dir.
Anything that is globally executable, lies under one of the directories in the $PATH variable (%PATH% on Windows).
For example, $PATH may look like this:
$ echo $PATH
/usr/local/opt/rbenv/shims:/Users/casraf/bin:/Users/casraf/bin:/usr/local/heroku/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/opt/fzf/bin
You may add directories to this list, separating with :, and each of these paths will be looked into when executing a command globally.
So you could either:
Save a copy of the executable in the gem exec dir:
ln -s /your/bin/file $(ruby -rubygems -e 'puts Gem.dir')
This will create a symbolic link to your bin, inside the regular gem executable dir (it should already be in your $PATH, if not, just add it:
export PATH=$(ruby -rubygems -e 'puts Gem.dir'):$PATH
You can put this in your .bashrc or .bash_profile to make sure it happens on every terminal session (if you have a non-standard setup, you may need to find another file to put this in)
Or just add the regular path to your PATH variable:
PATH=/path/to/gem/bin:$PATH

Why can't Git Bash run my executable?

I am on git-for-windows Git Bash. I can't run an executable on the command line:
Pedr#Abc-07 MINGW64 /c/dev
$ ls sqlite3.exe
sqlite3.exe*
Pedr#Abc-07 MINGW64 /c/dev
$ sqlite3
bash: sqlite3: command not found
Why is it so?
To run a program in the current directory in bash, you put ./ in front of it. So in your case:
$ ./sqlite3.exe
When you run sqlite3, bash will look for a program with exactly that name in all directories of the PATH environment variable, which by default includes standard locations for executables like /usr/local/bin but not your current directory. See here for more info on that.
It's because you're under a is a runtime environment for gcc, that give you support to binaries native under Windows, but you can run any exe as shell using ./ (local execute)
Take a look to documentation of this tool: http://sourceforge.net/p/mingw-w64/wiki2/FAQ/
Your PATH is missing ./. Add it to your .profile file in the home directory (/c/Users/username):
$ cd
$ pwd
/c/Users/username
$ echo 'PATH=$PATH:./' >> .profile
Restart bash session and voilĂ ! Now echo $PATH should output :./ as the last item. Note that you definitely need to add it as the last item for security (e.g. against malicious ls.exe).

Why is my Ruby Git script hook run with the wrong $PATH?

I'm using RVM. I wrote a Git pre-commit hook for a project:
#!/usr/bin/env ruby
puts RUBY_VERSION
puts `echo $PATH`
exit(1)
which outputs this when run by Git:
$ git ci -m 'foo'
1.8.7
/usr/libexec/git-core:/usr/bin:/usr/local/heroku/bin:/Users/mgoerlich/.rvm/gems/ruby-2.0.0-p195#global/bin:/Users/mgoerlich/.rvm/rubies/ruby-2.0.0-p195/bin:/Users/mgoerlich/.rvm/bin:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/platform-tools:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/tools:/usr/local/bin:/usr/local/sbin:/Users/mgoerlich/.dotfiles/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/bin/core_perl:/Users/mgoerlich/bin:/usr/local/share/npm/bin:/usr/local/share/npm/bin
It seems to run with the wrong version of Ruby because $PATH is not the same as in bash or zsh or sh. It seems like git is manipulating $PATH. When run manually, I get this:
$ .git/hooks/pre-commit
2.0.0
/usr/local/heroku/bin:/Users/mgoerlich/.rvm/gems/ruby-2.0.0-p195#global/bin:/Users/mgoerlich/.rvm/rubies/ruby-2.0.0-p195/bin:/Users/mgoerlich/.rvm/bin:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/platform-tools:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/tools:/usr/local/bin:/usr/local/sbin:/Users/mgoerlich/.dotfiles/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/bin/core_perl:/Users/mgoerlich/bin:/usr/local/share/npm/bin:/usr/local/share/npm/bin
In the output of the commit hook, there are two paths prepended, one of them /usr/bin where the system Ruby's executable is placed.
Is this a known behavior? Can I manipulate that somehow? I know I could specify the full path to the correct Ruby version in the shebang, but this is not what I want.
The reason i didn't wanted to use env instead of a fixed path to ruby or a rvm wrapper was that this is for a Team Project and not everyone in the Team is using RVM.
My final solution was to write my own wrapper script an add it to that project.
All client-side git hooks 're living in $PROJECT/bin/hooks, all of them ruby scripts.
Now, i've just put that mentioned wrapper in there, and created a symlink to that wrapper in $PROJECT/.git/hooks for all the hooks.
The script check's if RVM is used and if so fixes the $PATH var and if there are .ruby-version and/or .ruby-gemset files in the project root it loads the according version/gemset.
Then it'll run the according ruby script
Here's the wrapper in case you're interested:
#!/bin/bash
if [ -d "$HOME/.rvm/bin" ]; then
PATH="$HOME/.rvm/bin:$PATH"
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
if [ -f ".ruby-version" ]; then
rvm use "$(cat .ruby-version)"
fi
if [ -f ".ruby-gemset" ]; then
rvm gemset use "$(cat .ruby-gemset)"
fi
fi
ruby "bin/hooks/$(basename "$0").rb"
So, i'll get my rvm version/gemset and everybody else the ruby version they have in their PATH, and everyone is Happy.
you need to set ruby to a wrapper:
#!$rvm_path/wrappers/ruby-2.0.0-p195/ruby
You can simplify it with an alias:
rvm alias create git_hooks 2.0.0-p195
And then the ne shebang will look like this:
#!$rvm_path/wrappers/git_hooks/ruby
In the file just make sure to replace $rvm_path with /Users/mgoerlich/.rvm so finally it looks like:
#!/Users/mgoerlich/.rvm/wrappers/git_hooks/ruby
What I ended up doing is: the .git file structure:
.git/hooks/pre-commit
.git/hooks/pre-commit-main.rb
.git/hooks/pre-commit:
#!/usr/bin/env bash
export PATH="$THE_GOOD_PATH"
ruby "$GIT_DIR/hooks/pre-commit-main.rb"
.git/hooks/pre-commit-main.rb:
#!/usr/bin/env ruby
puts RUBY_VERSION
Then, when you call git commit, make sure that THE_GOOD_PATH, is defined:
export THE_GOOD_PATH="$PATH"
git commit
You could also export THE_GOOD_PATH="$PATH" from your .profile or the toplevel of your application and symlink all hooks to a single file.
This method has the advantage of being rbenv agnostic: it also works with RVM or Python virtualenv.
I wrote to the Git developers at: http://permalink.gmane.org/gmane.comp.version-control.git/258454 asking them to leave our PATH alone, but the initial reply was WONTFIX.

Using a #! comment in ruby running in Ubuntu

I am new to programming and am trying to follow an example which uses #! comment in ruby.
I am consistently get the message:
bash: matz.rb: command not found
I am using this comment:
#! /usr/bin/env ruby
I have tried it with and without the space after ! as well as with and without the env.
when I use the
$ which ruby
ruby is in: /usr/bin/ruby
I have also gone into the operating system and changed the permissions on the file matz.rb to rwx for all users w/ no effect. Am I doing something wrong or do I have my system set up incorrectly?
The /usr/bin/env part is fine. You need to give bash the path to matz.rb when you run it. If you're in the directory with matz.rb, type "./matz.rb". The directory "." means the current directory - bash doesn't look there by default when running programs (like Windows does).
The env program (/usr/bin/env) searches the executable search path - the PATH environment variable - for the ruby program as if you typed it at the command prompt, and runs that program. The shebang comment doesn't do this. If you want to give your script to other people who might not have ruby installed in the same place as you, then you should use the "#!/usr/bin/env ruby" comment so that it will work as long as they can run ruby by typing "ruby".
If you're in the same directory as the matz.rb file, be sure to run it as
$ ./matz.rb
and not just
$ matz.rb
Here's a shell session demonstrating this working:
$ ls -la m*
-rwxr-xr-x 1 gareth gareth 32 8 Jan 08:46 matz.rb
$ cat matz.rb
#!/usr/bin/env ruby
puts "Matz"
$ matz.rb
-bash: matz.rb: command not found
$ ./matz.rb
Matz
Your file wasn't created on Windows was it? If it has \r\n line endings, that will upset bash. You can open it with Vim and check:
vi matz.rb
:set ff=unix
:wq
If when you tab-complete the "ff=" part it says dos, then it has the wrong file format. Alternatively, run dos2unix and try to run the file again:
apt-get install sysutils
dos2unix matz.rb
It sounds like you're on a Unix/Linux system and just typing matz.rb on the command line. If you're trying to execute a command in the current directory, you need to call it like ./matz.rb. The "./" tells it to look in the current directory rather than just /usr/bin and friends.
I failed to see any answer indicating you to change the executable mode of the file, so you might wanna try and do
chmod +x matz.rb
before you go and try doing
./matz.rb
Also it might be better not to attach a .rb extension to the file, such is the case for normal ruby / rails scripts e.g. script/generate, script/console etc.
You can use the 'shebang' line with either:
#!/usr/bin/ruby
#!/usr/bin/env ruby
But the script needs to be executable (you indicated it is) and in your shell $PATH.
echo $PATH
Put the script in one of those directories, or modify your path, otherwise specify the full path to it, for example:
export PATH=$PATH:/home/user/bin
or one of these:
./matz.rb
/home/user/bin/matz.rb
You can also run the Ruby interpreter passing the script filename as an argument, and it will be executed. This is particularly useful if you have another version of Ruby installed on your system (say, for testing, like Ruby Enterprise Edition, REE):
/usr/bin/ruby matz.rb
/opt/ree/bin/ruby matz.rb
Have you tried the ShaBang as following to directly point to ruby?
#! /usr/bin/ruby
Then you call the script from the commandline as
./matz.rb
Under Unix/Linux systems the dot in front of a command to search for the command in the current directory. If you give a path like /usr/bin/ruby, it will search in the current directory for a directory called usr...
A command without a dot/ in front is searched in locations specified by the path variable of the environment.
A command with a / on the beginning is searched exactly from root following the specified path.
Inside your ShaBang, you want to specify the exact path to the interpreter so "/usr/bin/ruby" is the correct one. On the commandline, where you want your script to be executed, you need to call the script with "./matz.rb" otherwise the bash will search a command like /usr/bin/matz.rb what leads to your errormessage.

Resources