ZSH Autocomplete For Custom Script - terminal

I've been searching online for a lot of hours, puling an all nighter because i got so lost down this rabbit hole :D but i'm having trouble finding examples with working code.
I have a bash script that is called upon like the following examples:
foo-tools.sh switch <version number>
foo-tools.sh start
foo-tools.sh open-ports on
foo-tools.sh kube get logs
foo-tools.sh kube edit ing default-ingress -oyaml
I use zsh with oh-my-zsh as my shell.
I want to be able to type "foo-tools.sh " to list all availabe options and i want to be able to autocomplete an option with "foo-tools.sh k" meaning it should either list all availabe options starting with "foo-tools.sh k*" or if there is only one option autcomplete the command.
I found this code on some stackoverflow thread, it's the closes I've gotten to having it work fully:
#compdef foo-tools.sh
_foo_tools_sh() {
typeset -A opt_args
local alternatives
alternatives=(
'args:rv options:_foo_tools_sh_options'
)
_alternative $alternatives && return 0
return 1
}
_foo_tools_sh_options() {
local -a arguments=(
'start:Start VP'
'stop:Stop VP]'
'kube:Kube CMD'
'kube logs:Kube logs'
'info:Display info'
'get:Get CMD'
)
_sequence _describe 'cmds' arguments
return 1
}
# invoke the completion command during autoload
_foo_tools_sh "$#"
This works some what. When i type "foo-tools.sh " it shows me the options i configured:
all options displayed when TAB
But when i autocomplete one of the options with tab it adds a , after the command:
, added when TAB cmd
And the option with a space between the words, "kube logs" gets the space escaped when tabbed out:space escpaded + added ,
I also found these two commands, they goes in my .zshrc. The expansion is wierd, it ignores the commands that has spaces in them and it doesnt understand that the commands are nested.
I.e if typing foo-tools.sh open-ports it displays all the options, not just off/on.
local -a _foo_tools_sh=(
"start"
"stop"
"switch"
"install"
"kube"
"kube get"
"kube edit"
"open-ports on"
"open-ports off"
)
complete -W "${_foo_tools_sh}" 'foo-tools.sh'
Options not nestled
I would very much appreciate any help or insights in how to improve the script i have (or throw it out and replace it with something proper).

Related

Terraform GCP Instance Metadata Startup Script Issue

I've been working with Terraform, v0.15.4, for a few weeks now, and have gotten to grips with most of the lingo. I'm currently trying to create a cluster of RHEL 7 instances dynamically on GCP, and have, for the most part, got it to run okay.
I'm at the point of deploying an instance with certain metadata passed along to it for use in scripts built into the machine image for configuration thereafter. This metadata is typically just passed via an echo into a text file, which the scripts then pickup as required.
It's... very simple. Echo "STUFF" > file... Alas, I am hitting the same issue OVER AND OVER and it's driving me INSANE. I've Google'd around for ages, but all I can find is examples of the exact thing that I'm doing, the only difference is that theirs works, mine doesn't... So hopefully I can get some help here.
My 'makes it half-way' code is as follows:
resource "google_compute_instance" "GP_Master_Node" {
...
metadata_startup_script = <<-EOF
echo "hello
you" > /test.txt
echo "help
me" > /test2.txt
EOF
Now the instance with this does create successfully, although when I look onto the instance, I get one file called ' /test.txt? ' (or if I 'ls' the file, it shows as ' /test.txt^M ') and no second file.. I can run any command instead of echo, and whilst the first finishes, the second+ does not. Why?? What on earth is causing that??
The following code I found also, but it doesn't work for me at all, with the error, 'Blocks of type "metadata" are not expected here.'
resource "google_compute_instance" "GP_Master_Node" {
...
metadata {
startup-script = "echo test > /test.txt"
}
Okaaaaay! Simple answer for a, in hindsight, silly question (sort of). The file was somehow formmated in DOS, meaning the script required a line continuation character to run correctly (specifically \ at the end of each individual command). Code as follows:
resource "google_compute_instance" "GP_Master_Node" {
...
metadata_startup_script = <<-EOF
echo "hello
you" > /test.txt \
echo "help
me" > /test2.txt \
echo "example1" > /test3.txt \
echo "and so on..." > /final.txt
EOF
However, what also fixed my issue was just 'refreshing' the file (probably a word for this, I don't know). I created a brand new file using touch, 'more'd the original file contents to screen, and then copy pasted them into the new one. On save, it is no longer DOS, as expected, and then when I run terraform the code runs as expected without requiring the line continuation characters at the end of commands.
Thank you to commentors for the help :)

startup script in freebsd is not running

I have been trying to run a shell script at boot time of freebsd. I have read all simmilar questions in stackoverflow and tried. But nothing is worked. This is the sample code that i tried is dummy.
#!/bin/sh
. /etc/rc.subr
name="dummy"
start_cmd="${name}_start"
stop_cmd=":"
dummy_start()
{
echo "Nothing started."
}
load_rc_config $name
run_rc_command "$1"
Saved with name of dummy.
Permissions are -r-xr-xr-x.
in rc.conf file made dummy_enable="YES".
The problem is, when i rebooted my system to test, dummy file is not there. So script is not executing. what else need to do run my dummy script.
SRC:http://www.freebsd.org/doc/en/articles/rc-scripting/article.html#rc-flags
You need to add rcvar="dummy_enable" to your script. At least for FreeBSD 9.1.
Call your script with parameter rcvar to get the enabled status:
# /etc/rc.d/dummy rcvar
# dummy
#
dummy_enable="YES"
# (default: "")
And finally start it with parameter start - this won't start the service/script unless dummy_enable is set in /etc/rc.conf (or /etc/rc.conf.local, or /etc/defaults/rc.conf)
# /etc/rc.d/dummy start
Nothing started.
One possible explanation is that rcorder(8) says:
Within each file, a block containing a series of "REQUIRE", "PROVIDE",
"BEFORE" and "KEYWORD" lines must appear.
Though elsewhere I recall that if a file doesn't have "REQUIRE", "PROVIDE" or "BEFORE", then it will be arbitrarily placed in the dependency ordering. And, it could be that the arbitrary placement differs between the first run up to $early_late_divider and in the second run of those after $early_late_divider.
OTOH, is this a stock FreeBSD, or some variant? I recall reading that FreeNAS saves its configuration somewhere else and recreates its system files on every boot. And, quite possibly that /etc is actually on a ramdisk.
Also, /usr/local/etc/rc.d doesn't come into existence until the first port installing an rc file is installed.

Setting environment variables with puppet

I'm trying to work out the best way to set some environment variables with puppet.
I could use exec and just do export VAR=blah. However, that would only last for the current session. I also thought about just adding it onto the end of a file such as bashrc. However then I don't think there is a reliable method to check if it is all ready there; so it would end up getting added with every run of puppet.
I would take a look at this related question.
*.sh scripts in /etc/profile.d are read at user-login time (as the post says, at the same time /etc/profile is sourced)
Variables export-ed in any script placed in /etc/profile.d will therefore be available to your users.
You can then use a file resource to ensure this action is idempotent. For example:
file { "/etc/profile.d/my_test.sh":
content => 'export MYVAR="123"'
}
Or an alternate means to an indempotent result:
Example
if [[ ! grep PINTO_HOME /root/.bashrc | wc -l > 0 ]] ; then
echo "export PINTO_HOME=/opt/local/pinto" >> /root/.bashrc ;
fi
This option permits this environmental variable to be set when the presence of the
pinto application makes it warrented rather than having to compose a user's
.bash_profile regardless of what applications may wind up on the box.
If you add it to your bashrc you can check that it's in the ENV hash by doing
ENV[VAR]
Which will return => "blah"
If you take a look at Github's Boxen they source a script (/opt/boxen/env.sh) from ~/.profile. This script runs a bunch of stuff including:
for f in $BOXEN_HOME/env.d/*.sh ; do
if [ -f $f ] ; then
source $f
fi
done
These scripts, in turn, set environment variables for their respective modules.
If you want the variables to affect all users /etc/profile.d is the way to go.
However, if you want them for a specific user, something like .bashrc makes more sense.
In response to "I don't think there is a reliable method to check if it is all ready there; so it would end up getting added with every run of puppet," there is now a file_line resource available from the puppetlabs stdlib module:
"Ensures that a given line is contained within a file. The implementation matches the full line, including whitespace at the beginning and end. If the line is not contained in the given file, Puppet appends the line to the end of the file to ensure the desired state. Multiple resources can be declared to manage multiple lines in the same file."
Example:
file_line { 'sudo_rule':
path => '/etc/sudoers',
line => '%sudo ALL=(ALL) ALL',
}
file_line { 'sudo_rule_nopw':
path => '/etc/sudoers',
line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
}

How to make a ruby command line application with pager?

I'm making a command line tool using Ruby. It will print a lot of text on screen. Currently, I'm using shell pipeline (may_app | more) to do so. But I think it's better to has a default pager.
It's just like what you see when execute git log . One can disable pager by using git --nopager log.
I've done quite much google work and find one gem: hirb , but it seems a little overkill.
After many tries, I'm current using shell wrapper to do so:
#!/bin/bash
# xray.rb is the core script
# doing the main logic and will
# output many rows of text on
# screen
XRAY=$HOME/fdev-xray/xray.rb
if [ "--nopager" == "$1" ]; then
shift
$XRAY $*
else
$XRAY $* | more
fi
It works. But is there a better way?
You are doing it right. But instead using more you'd better get a pager from $PAGER environment variable, if any.
Some people prefer less to more for example, and others have their favorite parser options set in this var.
You can use the pipe in Ruby via a call to system and provide the options (along with a nice help interface) like so:
require 'optparse'
pager = ENV['PAGER'] || 'more'
option_parser = OptionParser.new do |opts|
opts.on("--[no-]pager",
"[don't] page output using #{pager} (default on)") do |use_pager|
pager = nil unless use_pager
end
end
option_parser.parse!
command = "cat #{ARGV[0]}"
command += " | #{pager}" unless pager.nil?
unless system(command)
STDERR.puts "Problem running #{command}"
exit 1
end
Now, you support --pager and --no-pager on the command line, which is nice to do.

Startup Items - Creating a basic one

Please save me from a potential nervous breakdown!
I've been following Apples documentation (see below) on how to create a Startup Item. Currently I'm just trying to get my script to print something to the console, much less actually run my app.
Here are my two scripts, one is the startup executable, the other is the plist:
#!/bin/sh
. /etc/rc.common
# The start subroutine
StartService() {
# Insert your start command below. For example:
echo "hey Eric we've started"
# End example.
}
# The stop subroutine
StopService() {
# Insert your stop command(s) below. For example:
echo "STOPPED ERIC"
# End example.
}
# The restart subroutine
RestartService() {
# Insert your start command below. For example:
echo "RESTART ERIC"
# End example.
}
RunService "$1"
{
Description = "Software Update service";
Provides = ("SoftwareUpdateServer");
Requires = ("Network");
Uses = ("Network");
OrderPreference = "Late";
Messages =
{
start = "Starting Software Update service";
stop = "Stopping Software Update service";
};
}
Using terminal I tried to set the permissions as closely as possible as to how it is documented in the example in the link below. The odd thing was that the files didn't show the 'root' aspect to their ownership.
I then ran SystemStarter start theApp and nothing happens. Absolutely nothing.
Any help?
http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/StartupItems.html
You should not create a Startup Item any more. It's a legacy mechanism and superseded by launchd. Write a plist for launchd instead. I know this is not the help you wanted, but sadly with Apple, you need to follow the mothership...
Read this section of the same document instead.
See the document just you quoted yourself:
Note: The launchd facility is he preferred mechanism for launching daemons in Mac OS X v10.4 and higher. Unless your software requires compatibility with Mac OS X v10.3 or earlier, you should use the launchd facility instead of writing a startup item. For more information, see “Guidelines for Creating and Launching Daemons.”
Note that v10.4 become available in 2005.

Resources