Changing directory in ubuntu with Ruby and a command line tool - ruby

#!/home/user/.rvm/rubies/ruby-2.0.0-p353/bin/ruby
case ARGV[0]
when "apache"
exec('cd /etc/apach2')
exec('sudo nano httpd.conf')
#...
end
I am trying to make a quick command line tool that will change directories for me with one word.. so from the command line (in ubuntu 12). It tells me it cant cd.. But I try the command myself and it will work just fine.

Ruby's Dir class is your friend for this, check-out the chdir method:
Dir.chdir('/path/to/change/to')
will change Ruby's concept of the current working directory for the time the code is running. Any sub-shells would consider that their starting directory.
You can also pass chdir a block, and all code in that block will assume the new directory, which will then revert to the old one when the block exits:
Dir.chdir('/path/to/change/to') do
# do some stuff
end

OK, so I did this and it works (I'm on OS X but should be the same):
ARGV[0]
when "testme"
system('cd ripple')
system('ls -al')
#...
end
calling system('cd ... does not change move you to that directory in the current shell you are executing your .rb file in. So it would make more sense to do:
system('sudo nano /etc/....
all on one line
I tested it with back ticks and it didn't work at all for me.
I tested with exec() and got the expected result, it runs one line and that's it. So exec() could work if you only have one command to run or you chain them all together with &&
exec('ls /etc && sudo nano /etc/....
I would read this: http://rubyquicktips.com/post/5862861056/execute-shell-commands

Related

fish shell prompt: fish not reading fish_prompt.fish nor fish_right_prompt.fish

To make some minor changes to the fish prompt, I modified fish_prompt.fish/fish_right_prompt.fish files in the ~/.config/fish/ directory, but that does not change anything.
'functions --details fish_prompt' returns nothing, and 'functions --all fish_prompt' spits out:
# Defined via `source`
function fish_prompt
set -l last_status $status
if set -q CONDA_LEFT_PROMPT
__conda_add_prompt
end
return_last_status $last_status
__fish_prompt_orig
end
Where do I need to go from here to modify the prompt - I just need to add timestamp and a newline at the end of the prompt?
I have omf, git-plugin installed both of which might be superseding the fish_prompt and fish_right_prompt functions. I am on a ubuntu system. Thanks for your help!
Though there are several fish_prompt.fish functions scattered around - eight of them in my case as revealed by the 'find' command, the one that seems to matter under omf is:
~/.local/share/omf/themes/<your_current_theme>/fish_prompt.fish
I ended up modifying that to get to what I wanted!

Launch interactive Bash shell in Ruby script, with initial command

I'm working on an interactive Ruby script, which build and packages resources. In the middle of the process, I'd like to drop into an interactive shell, but pre-cd'd into a specific working directory, as well as with an explanatory message (CTRL-D to continue). The interactive bash + given initial command is what's problematic.
Per the answer for doing something like this in Bash, given at https://stackoverflow.com/a/36152028, I've tried
system '/bin/bash', '--init-file', '<(echo "cd ~/src/devops; pwd")'
However, bash runs interactively but completely ignores the '<(echo "cd ~/src/devops; pwd")' section.
Interestingly system '/bin/bash', '--init-file complains if no argument is given, but literally anything runs bash, but with no initial command.
*Note that (--rcfile instead of --init-file) has the same effect.
Change the working directory of the Ruby script first, so that bash inherits the correct working directory.
curr_dir = Dir.pwd
Dir.chdir("#{Dir.home}/src/devops")
system "/bin/bash"
Dir.chdir(curr_dir) # Restore the original working directory if desired
Oh, this is probably far better (you can probably guess how little familiarity I have with Ruby):
system("/bin/bash", :chdir=>"#{Dir.home}/src/devops")

How do I make a Ruby script into a bash command?

I have a Ruby file, and I run it as ruby file.rb "parameters". I prefer to run it as regtask parameters without having to include ruby and the filename every time. I want it to be on the same level as ls. How would I accomplish this?
Edit your file, make sure this is the first line, so your system knows how to execute your file:
#!/usr/bin/env ruby
Next, change the file's permissions to make it executable:
chmod a+x file.rb
And finally, rename it and move it somewhere where it will be executed without having to write its full path:
mkdir -p ~/bin
mv file.rb ~/bin/regtask
(Most systems will automatically add ~/bin to PATH if it exists; if not, you will have to add it to PATH yourself in your startup files.)
This should help.. Please let me know if you run into any issues.
http://commandercoriander.net/blog/2013/02/16/making-a-ruby-script-executable/
Making a Ruby Script Executable
It's common knowledge in the *nix community, but for many new developers turning a Ruby script into an executable command line program is akin to magic. While there are other references on the internet, for the post here, I will briefly explain how to go from running a Ruby script by invoking Ruby directly, to running the script by its name alone.
We will start by assuming we have a simple Ruby script which prints "hello" on the command line. Our script's name will be greeter.rb. The file holds one line of Ruby code:
puts "Hello!"`
To run the script, we must type ruby greeter.rb. Wouldn't it be nice to just type greeter instead and still get the script to run? Yes, it would.
First, we need to tell Bash what to do with our file since we won't be passing the script to Ruby directly. To do that, we add the following to the very top of our script:
#!/usr/bin/env ruby
puts "Hello!"
The first line is a Bash directive and basically tells Bash what program to run our file with by asking for the current configured version of Ruby as specified by the env command. For more on how env works, try typing man env into the command line.
Second, we need to make our script executable, which requires changing the file permissions. If the concept of file permissions is new, read about it here. Bascially, files have three types of permissions. They can be read, written, and executed. Most files typically start out as only having read and write access. Since we want to execute our script, we're going to have to grant it execute permissions.
Doing that is just a simple Bash command. On the command line, navigate to the directory holding the greeter.rb file. Now, to check the permissions, run:
ls -l greeter.rb
The output will look something like this:
-rw-r--r-- 1 username staff 13 Feb 16 21:10 greeter.rb
Your own username will show up in the place of username, and the creation date will naturally be different, but otherwise the output will be almost identical. The first part of the line is the revelant part. The letters r and w specify read and write permissions.
We're going to add execute permissions which will appear as an x in that line. To add execute permissions, run the following command.
chmod 755 greeter.rb
Now, if you check the file permissions again with ls -l greeter.rb, the output should be a little different.
-rwxr-xr-x 1 username staff 13 Feb 16 21:20 greeter.rb
The presence of x indicates that the file can be run directly without calling Ruby first. The following command should get our file to say "hello."
./greeter.rb
Almost there. Now, we just need to get rid of the prefix ./, which tells Bash where to look for greeter.rb, i.e., in the current directory. Before we complete this last step, though, let's rename our file to just greeter.
mv greeter.rb greeter
Now, for the last step. Everytime we call a Bash program, e.g., ls, chmod, mv, etc., Bash searches through a predefined list of folders looking for those programs. This is called the path. To see what the path is set to on your computer, try:
echo "$PATH"
The output should be a long string of various system-critical folders. We need to put our application into one of these folders. Traditionally, it's best to leave folders like /usr/bin/ and /bin/ alone. Instead, any kind of user additions should be placed in /usr/local/bin/. If that folder doesn't exist, create it with:
mkdir -p /usr/local/bin/
Now, we can either move our greeter into that folder, or leave the application where it is and just create a softlink (or an alias in OS X terms) within the /usr/local/bin/ folder. To create an alias, we'll use the ln command. From the directory where greeter lives, type:
ln -s $PWD/greeter /usr/local/bin/
Note that the $PWD variable will expand to an absolute path to our greeter script. Now, we're done and we can simply type greeter to invoke our Ruby script!
As a footnote, if any of the above Bash commands seem confusing, trying looking up their man page by typing man <command>.

Check for existing directory fails in Ruby + Chef

This is my piece of Ruby in a Chef recipe:
# if datadir doesn't exist, move over the default one
if !File.exist?("/vol/postgres/data")
execute "mv /var/lib/postgresql/9.1/main /vol/postgres/data"
end
The result is:
Executing mv /var/lib/postgresql/9.1/main /vol/postgres/data
mv: inter-device move failed: `/var/lib/postgresql/9.1/main' to `/vol/postgres/data/main'; unable to remove target: Is a directory
I know that /vol/postgres/data exists and is a directory, yet it still attempts to execute the mv. Why?
Just to be sure, running the following standalone Ruby script on the same machine outputs "nomv":
if !File.exist?("/vol/postgres/data")
print "mv"
else
print "nomv"
end
I was not so attentive earlier, I thought you are checking for file existence in not_if or only_if block. Your problem is similar to the one in this question: Chef LWRP - defs/resources execution order. See the detailed explanation there.
Your problem is that !File.exist?("/vol/postgres/data") code gets executed straight away - (because it's pure ruby), before any resource is executed and thus before the postgress is installed.
The solution should be to move the check to not_if block.
execute "mv /var/lib/postgresql/9.1/main /vol/postgres/data" do
not_if { File.exist?("/vol/postgres/data") }
end
Use this block of code :
execute "name" do
command "mv /var/lib/postgresql/9.1/main /vol/postgres/data"
not_if { ::File.exists?("/vol/postgres/data")}
end
OR
you can also use
execute "name" do
command "mv /var/lib/postgresql/9.1/main /vol/postgres/data"
creates "/vol/postgres/data"
end
Both will run the command only if /vol/postgres/data is not present in the file system.
If you want to run block of commands then use something like this,
bash 'name' do
not_if { ::File.exists?("/vol/postgres/data") }
cwd "/"
code <<-EOH
mv /var/lib/postgresql/9.1/main /vol/postgres/data
#any other bash commands
#any other bash commands
EOH
end
I use
!::File.directory?(::File.join('path/to/directory', 'directory_name'))
To test if a directory exists you can use an equvivalent of File.exists which is Dir.exist:
Dir.exist?("/vol/postgres/data")
As others pointed out, you should use not_if or only_if instead of using plain Ruby condition, so I'm not going to explain it again. Check Draco's answer for details.
execute "mv /var/lib/postgresql/9.1/main /vol/postgres/data" do
not_if { Dir.exist?("/vol/postgres/data") }
end
I would use, !File.directory?("/vol/postgres/data")
Are you calling it within your rails application or it is a standalone ruby file.
If you are doing in your rails app.
Then,
File.exist?("#{Rails.root}/ur-file-path")
Ex: File.exist?("#{Rails.root}/public/ur-filename")
You need to specify the particular file path from root.
A quick google search turns up a lot of answers regarding "inter-device move failed". Ruby is just passing along the error returned by the operating system; this has nothing to do with testing the file as the other answers indicate.
From: http://insanelabs.com/linux/linux-cannot-move-folders-inter-device-move-failed-unable-to-remove-target-is-a-directory/
This is somewhat simple as long as we understand the concept. mv or move does not actually move the file/folder to another location within the same device, it merely replaces the pointer in the first sector of your device. The pointer (in inode table) will be moved, but nothing is actually being copied. This will work as long as you stay within the same media/device.
Now, when you try to move files from one device to another (/dev/sda1 to /dev/sdb1) you will run into “inter-device move failed, unable to remove target: Is a directory” error. This happens when mv has to actually move your data to another device, but cannot remove the inode/pointer, because if it did then there will be no data to fall back to, and if it didn’t then mv operation is not really complete because we will end up with data in source. Damned if you do and damned if you don’t, so it’s wise not to do it to begin with!
In such situation cp is best. Copy your data over and then remove your source manually.
A better solution might be to just use ruby tools instead of executing a shell command, since it says If file and dest exist on the different disk partition, the file is copied then the original file is removed.
FileUtils.mv '/var/lib/postgresql/9.1/main', '/vol/postgres/data'

Unable to initialize device PRN message upon executing .rb-Script in cygwin

The headline should pretty much say it all. I'm using windows 7, installed cygwin, set it up, created a .rb-File which looks like this:
print "Test"
(Impressive stuff, eh?)
Now, using Cygwin, I want to execute it, I tried
chmod +x ruby.rb
afterwards
./ruby.rb
The following message comes up:
Unable to initialize device PRN
Any ideas?
Thanks!
You forgot the "she-bang" line. Without it it will be interpreted as a bash script, not a ruby script.
The print command that bash finds is Window's print.exe, which wants to print to a physical priner, rather than print to the screen.
Add "#!/usr/bin/env ruby" as the first line of the file.

Resources