Using case statement within select loop - bash

I am currently doing bash programming wherein I am using case statement within select loop.However,whenever I enter any input, the control goes to default case and not the case which it should actually go to.For eg. when I enter date,instead of going to date case, it goes to default case. Can anybody of you notice some error?
#!/bin/bash
select command in date pwd ls
do
case $command in
date)date;;
pwd)pwd;;
ls)ls;;
*)echo"wrong";;
esac
done

[...] when I enter date,instead of going to date case, it goes to default case.
The select builtin works with numbered options. You need to enter 1 for the first option "date", 2 for the second option "pwd", and so on.
The relevant parts from help select:
select: select NAME [in WORDS ... ;] do COMMANDS; done
[...] If the line consists of the number
corresponding to one of the displayed words, then NAME is set
to that word. If the line is empty, WORDS and the prompt are
redisplayed. If EOF is read, the command completes. Any other
value read causes NAME to be set to null. [...]

Related

Bash script select option based on value

I have a command I would like to run in terminal.
eg.
samplecommand -s
Which provides an option later on:
Option 1
Option 2
with the input question
Please enter an index:
So I would need to input 2 into terminal.
However, the order of Option 1 and Option 2 change making it hard to hard code a specific index.
e.g. it could be:
Option 2
Option 1
Is there a way to use the context of options provided and make the script select only "Option 2".
You can use se;ect:
> select: select NAME [in WORDS ... ;] do COMMANDS; done
> The WORDS are expanded, generating a list of words. The
> set of expanded words is printed on the standard error, each
> preceded by a number. If `in WORDS' is not present, `in "$#"'
> is assumed. The PS3 prompt is then displayed and a line read
> from the standard input. If the line consists of the number
> corresponding to one of the displayed words, then NAME is set
> to that word. If the line is empty, WORDS and the prompt are
> redisplayed. If EOF is read, the command completes. Any other
> value read causes NAME to be set to null. The line read is saved
> in the variable REPLY. COMMANDS are executed after each selection
> until a break command is executed.

Suppress quote character in bash completion

I am adding bash completion for some parameters of a query that users can enter on the command line to a script. Something like:
foo.py 'select abc(), def
Here I am completing the column names abc() and def. The problem that I am facing is that bash is automatically adding the ending single quote which is a hindrance to users. They might want to continue writing the query. Note that I need to use the single quotes while accepting the query as the query can contain parenthesis.
For example,
foo.py 'select ab<TAB>
should result in:
foo.py 'select abc(
instead of:
foo.py 'select abc('
My completion function returns select abc( but it seems that bash is inserting the extra closing quote that I want to get rid of. Any ideas how to do this?
Completion function used:
_egg_autocomplete_()
{
case "$COMP_CWORD" in
2)
readarray -t COMPREPLY < <( ./suggest.py order $2 )
;;
esac
}
suggest.py contains the actual code which prints suggested completions one per line. The suggestions can contain spaces in them.
I found the following at https://tiswww.case.edu/php/chet/bash/NEWS but was unable to make it work:
j. New application variable, rl_completion_suppress_quote, settable
by an application completion function. If set to non-zero,
readline does not attempt to append a closing quote to a completed
word.
I added the following line to my ~/.inputrc file but it didn't cause any difference:
set rl_completion_suppress_quote 1
Bash version used: GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu)

Put select result in a ksh variable

using sql loader, I know I can reference a ksh variable in my ctl file. For example I can write
LOAD DATA
INFILE '$PATH_IN_KSH/my_file.dat'
...
I would like to add a WHEN clause like this
WHEN (125:125) = '$P_NUMBER'
P_NUMBER would have the value of a column in a table that I would retrieve with a select query.
Is it possible to do that ? retrieve a value from a column with a select and somehow put it in the ksh variable so the ctl file can see it. (something with sql plus?)
Thank you
As a basic outline you can run SQL*Plus with a heredoc to perform the query, and assign the output to a variable:
P_NUMBER=`sqlplus -s /nolog <<!EOF
connect username/password
whenever sqlerror exit failure
set pagesize 0
set feedback off
select your_value from your_table where your_key = 'something';
exit 0
!EOF`
Enclosing in backticks assigns the result to the variable. $P_NUMBER will then hold whatever value your query got (or an error message if the credentials were wrong, say). It helps if you're sure the query will return exactly one result. You can also test the return code with $? to look for errors, before you try to use your variable.
Including the -s flag, turning off feedback and setting the pagesize to zero collectively suppress all the noise so you only get the result and don't have to strip out banners, headings etc.
And finally I've used /nolog and put the connect statement inside the heredoc so that the credentials don't appear in the process list, which is an often-overlooked security issue. If you don't want to do that and do put the credentials as sqlplus username/passwd, you can add the -l flag so that it only tries to log in once; otherwise if login fails for some reason it'll try to use the rest of the heredoc as further credentials, and can appear to get hung up with short scripts.

Assign BASH variable from file with specific criteria

A config file that the last line contains data that I want to assign everything to the RIGHT of the = sign into a variable that I can display and call later in the script.
Example: /path/to/magic.conf:
foo
bar
ThisOption=foo.bar.address:location.555
What would be the best method in a bash shell script to read the last line of the file and assign everything to the right of the equal sign? In this case, foo.bar.address:location.555.
The last line always has what I want to target and there will only ever be a single = sign in the file that happens to be the last line.
Google and searching here yielded many close but non-relative results with using sed/awk but I couldn't come up with exactly what I'm looking for.
Use sed:
variable=$(sed -n 's/^ThisOption=//p' /path/to/magic.conf)
echo "The option is: $variable")
This works by finding and removing the ThisOption= marker at the start of the line, and printing the result.
IMPORTANT: This method absolutely requires that the file be trusted 100%. As mentioned in the comments, anytime you "eval" code without any sanitization there are grave risks (a la "rm -rf /" magnitude - don't run that...)
Pure, simple bash. (well...using the tail utility :-) )
The advantage of this method, is that it only requires you to know that it will be the last line of the file, it does not require you to know any information about that line (such as what the variable to the left of the = sign will be - information that you'd need in order to use the sed option)
assignment_line=$(tail -n 1 /path/to/magic.conf)
eval ${assignment_line}
var_name=${assignment_line%%=*}
var_to_give_that_value=${!var_name}
Of course, if the var that you want to have the value is the one that is listed on the left side of the "=" in the file then you can skip the last assignment and just use "${!var_name}" wherever you need it.

bash dynamic dialog

I have a task to write simple bash script that adds deletes and views entries from file.
The requirement is to use "dialog"
data structure in file:
Name Surname mymail#mail.com
Another New person#database.loc
basically i have accomplished everything except delete, i know how to do the delete itself(with "sed" i think?)
But i need to use dialog --menu to display the search results.
The menu item should be whole line of text i think as after selection of an item i will use "grep" again to filter out the unique entry.
Maybe anyone can put me on the right direction?
Thanks.
I used dialog never before, but maybe I still can help. Try this:
declare -a args=()
while read
do
args+=("$REPLY" "")
done < <( grep '#' example.txt )
dialog --menu "Please select the line you want to edit" 40 60 34 "${args[#]}"
How does this work?
dialog --menu takes the following arguments:
question text
height and width of the window
height of the menu (which should be 7 less then the window height to use it fully, in my experience)
pairs of tag string and description.
The selected tag string is then output (on stderr) at the end.
How to create such a list strings from our grep output? A failed try is described below, here the working one.
The read command reads one line a time from standard input (to which we redirected the grep output), and puts it (if we don't give other options or arguments) in the REPLY variable.
We then add this value (quoted to be one element) to the array args , and additionally a single "" to add an empty string to the array, too.
We have to use the < <( ... ) syntax for redirection, since the normal | creates a subshell for the second command, which has the effect that changes to the variables are not propagated back to the original shell. (< means read input from file, and <( ... ) creates a pipe to read the output of the command and results in its filename.)
Then we use the "${args[#]}" parameter expansion - # has the effect that each element is individually quoted as the result. So for your example, the command line now looks like
dialog --menu "Please select the line you want to edit" 40 60 34 "Name Surname mymail#mail.com" "" "Another New person#database.loc" ""
This creates a two line menu, with the complete lines as the "tag", and an empty string as the clarification.
You will need some way to capture it's standard error output, as it puts the result there.
Another idea which does not work:
The question is how to to get the output of grep in the command line of dialog, so that it forms two arguments for each line.
What helps here are the following syntactic constructs:
Command substitution: $( cmd ) executes the command and converts the result to a string, which is then used at the point in the command line.
So, we need some command which produces two "words" for each line of grep output (since your file would give three words). As you are already using sed, why not use it here too?
The sed command s/^.*$/"&" ""/ replaces each line with the line enclosed in "", followed by another two quotes.
"Name Surname mymail#mail.com" ""
"Another New person#database.loc" ""
The idea would now be to use
dialog --menu "Please select the line you want to edit" 40 60 34 $( sed -e 's/^.*$/"&" ""/' < input )
but unfortunately the word-splitting of bash does not respect "" after command-substitution, so bash gives the six arguments "Name, Surname, mymail#mail.com", "", "Another, New, person#database.loc" and "" to the dialog program. (In fact, using "" to inhibit splitting seems to work only for quotes given literal in the source or in eval - but eval does not work here since we have line breaks, too.)

Resources