Passing multiple arguments in bash (without getopt) - bash

I have a bash script I am working on where I need to pass two arguments into a function. When I run the script everything works fine, except when it parses through the file I pass to it, the result I always get is Association (this is written in the text file). Can you advise what I would need to do so that it parses the correct info, which should be what I would type in as uid? I wrote in the input 123456789 because that's in the text file, but again I am getting Association as the result instead.
echo "Please enter the UID: ";
read uid
echo "Please enter server file: ";
read server
uidAssoc(){
arg1=$1
arg2=$2
for arg1 in $(cat ~/jlog/"$2"); do awk 'match($i, $2){ print substr($i, RSTART, RLENGTH)} ' ~/jlog/"$2";done;}
uidAssoc "$uid" "$server"
exit

The closing brace of the function requires whitespace in front of it (reference). Formatting your code more readably will help.
uidAssoc(){
arg1=$1
arg2=$2
for arg1 in $(cat ~/jlog/"$2"); do
awk 'match($i, $2){ print substr($i, RSTART, RLENGTH)} ' ~/jlog/"$2"
done
}
Some questions for you:
Why do you assign arg1 and arg2 but never use them?
What is $i in your awk script? (since i is unset, that will eventually evaluate to the whole line)
Are you aware that the $2 inside single quotes is different from the $2 outside of single quotes?

Related

Writing an equivalent of Python's input function in bash

I am trying to write a simple equivalent of Python's input function in Bash.
An example in a Python script would be something like this:
s = input('Please input something: ')
I imagine the call to a Bash equivalent would look like this:
s=$(input "Please input something: ")
This is the implementation that I wrote:
function input {
# $1 is the prompt passed as an argument; in my above example,
# it would be 'Please input something: '
printf "%s" "$1"
read in
echo "${in}"
return 0
}
With the call s=$(input "Please enter something: "), the prompt never prints; instead, the Bash script simply waits for user input without ever displaying the text. Pressing Enter, that is, giving no input, sets s to the prompt itself. What seems to be happening is s captures the output from the line printf "%s" "$1", then reads input which it also echoed back. I have also tried explicitly directing the prompt to stdout with printf "%s" "$1" >&1, but to no avail.
How can I print the prompt first, then capture input and echo it back to the calling function?
You're in luck. It already exists in the form of read -p.
read -p 'Please input something: ' s
To be safe, it's a good idea to use IFS= and -r as well. IFS= makes sure leading and trailing whitespace are retained. -r preserves backslashes so \n isn't interpreted as a newline, or \\ turned into \.
IFS= read -rp 'Please input something: ' s
As to why your function doesn't work, it's because the prompt is being printed to stdout, which is captured. Print to stderr to get it to show up.
input() {
printf "%s" "$1" >&2
read in
printf '%s\n' "$in"
}
A careful scripter will use printf '%s\n' in place of echo. If the user types -n or -e you want those printed, not interpreted as options.

grep on variable passed to function

I am passing a variable to a function that has been loaded from a config file. This variable is in turn passed on to a grep. I have tried several ways to expand the search variable ($1) but none seem to work, however the file to search works fine ($2).
Can someone advise what is the correct way to present the variable to the grep function. I have tried
"$1", "${1}", $1, ${1}, "${!1}
UPDATE Based on answers I have updated the script.sh to refelect the actual script complexity as it still does not work.
thanks
Art
Working code with no variable for RouteTableId
MyVar=$(grep -m 1 "RouteTableId" $2)
Not Working code with variable for RouteTableId
config.file
myTerm="RouteTableId"
myFile="my.file"
script.sh
. config.file
myFunction(){
mySubFunction(){
myVar=$(grep -m 1 "$1" $2)
echo $myVar
}
mySubFunction ${!1} ${!2}
}
myFunction "myTerm" "myFile"
UPDATE
I have done some more tests and it turns out that when passing variables between functions, in some circumstances the numbering order changes if one of the sequence is null. for example if i call myFunction with the following, the 2nd variable being null
myFunction "myTerm" "blah" "myFile"
then myFunction will see the following
echo "${!1}, ${!2}, ${!3}"
RouteTableId,,my.file
and then passing this to mySubFunction
mySubFunction ${!1} ${!3}
gives from within mySubFunction
echo "${!1}, ${!2}, ${!3}"
RouteTableId,my.file,
so it seems the null is being removed in the order and the subsequent variables are being brought forward in the number order.
If someone can validate and explain why I would appreciate it.
thx
Art
You are not passing the values of the variables but the variable names themselves as values.
i.e.
myFunction "myTerm" "myFile"
should be
myFunction "$myTerm" "$myFile"
If this isn't what you expect, you should edit your question to better define what it is you do expect:
$ cat my.file
foo
Here it is: RouteTableId
bar
$
$ cat config.file
myTerm="RouteTableId"
myFile="my.file"
$
$ cat script.sh
. config.file
myFunction() {
mySubFunction() {
myVar=$(grep -m 1 "$1" "$2")
echo "$myVar"
}
mySubFunction "${!1}" "${!2}"
}
myFunction "myTerm" "myFile"
$
$ ./script.sh
Here it is: RouteTableId
From your recent update, I think you are confused about what $1, etc. means. In a shell script but outside of any function $1 is the first arg passed to the shell script. In a function within a shell script $1 is the first arg passed to that function, NOT the first arg passed to the shell script. So if you do:
func() {
echo "$1,$2,$3"
}
func "$1" "$3"
then you will get the values of the first arg passed to the script (since that is also the 1st arg passed to the function), then a comma, then the 3rd arg passed to the script (since that is the 2nd arg passed to the function) and then another comma and that is all (because there is no 3rd arg passed to the function).
Hope that makes sense.

Accessing Shell parameters inside functions

So I'm playing around with a simple bash program, simply to learn the basics of shell and bash. The idea is a tiny password generator that saves passwords to a .txt file. Keep in mind, this is simply something to learn shell scripting - of course I understand the premise is unsafe :)
For example, I want to be able to write
./script.sh facebook generate
Which would generate a simple string and then if I confirm - save the password and site name to the .text file.
Anyways, the problem I am having is - I'm unable to retrieve the $1 and $2 parameters on the line in which I am echoing the text to the txt file (see below). I've put a comment on the line that I can't get to work. I just get blanks in the .txt file.
Can anyway help and give some guidance on accessing the parameters inside functions?
function generate() {
PASS="9sahdoasndkasnda89zls"
echo $PASS
}
function storeConfirm() {
/bin/echo -n "Do you want to store this password? Y/N "
read answer
if [ "$answer" == "Y" ]
then
echo "--------" >> pwstore.txt;
echo $1 "=" $2 >> pwstore.txt; #This line doesn't work, can't seem to access the $1 and $2 params
echo "Successfully stored for you"
else
echo "Ok... have it your way"
fi
}
if [[ $2 == "generate" ]]; then
generate
echo "for site=" $1
storeConfirm
fi
Since you can pass parameters to a function in the same way you can pass parameters to a script you have to make sure the script parameters get "forwarded" to the function. In other words - a function has its own "parameter scope". An example:
$ cat script
#!/usr/bin/env bash
_aFunction(){
echo "Parameter 1: ${1}"
echo "Parameter 2: ${2}"
}
_aFunction
_aFunction "$1" "$2"
_aFunction One Two
$ ./script 1 2
Parameter 1:
Parameter 2:
Parameter 1: 1
Parameter 2: 2
Parameter 1: One
Parameter 2: Two

how to pass multi-line output from pipe to a variable in bash? without using temp file

I have a complex grep/awk/etc command line which use some " some $var already, which makes it even impossible to use
VAR="$( that command )"
to get all output
I don't want to create temp files, which make it even ugly,
is it possible to pass pipe output into a variable in bash
like
command | > $VAR
Just use the : VAR=$(complex command ), writing complex command exactly as you would if you were writing it on the next line.
Ex: if you have
foo=1
bar="2 3"
awk -v myfoo="$foo" -v mybar="$bar" '..... complex
awk
script here .....'
you could put that into VAR with:
foo=1
bar="2 3"
VAR="$( awk -v myfoo="$foo" -v mybar="$bar" '..... complex
awk
script here .....' )"
ie, once inside $(...), bash is reading things as if it was at the "first level". It works as $(...) is evaluated first before the line containing it is evaluated.
You can do a for loop as following (Just a warning, for loop split output by space. So you'll got a word by iteration):
#!/usr/bin/ksh
for RC_OUTPUT in $(./testEcho.ksh)
do
echo $RC_OUTPUT
done
Here a more complex solution (max line lenght = 80):
#!/usr/bin/ksh
LINE_LENGTH_MAX=80
LINE_LENGTH=0
for RC_OUTPUT in $(./testEcho.ksh)
do
CURRENT_LENGTH="$(expr length $RC_OUTPUT)"
(( LINE_LENGTH = LINE_LENGTH + CURRENT_LENGTH + 1 ))
if [[ $LINE_LENGTH -gt $LINE_LENGTH_MAX ]]
then
LINE_LENGTH=$CURRENT_LENGTH
echo $RC_OUTPUT
else
echo -n "$RC_OUTPUT "
fi
done

Passing a string with spaces as a function argument in Bash

I'm writing a Bash script where I need to pass a string containing spaces to a function in my Bash script.
For example:
#!/bin/bash
myFunction
{
echo $1
echo $2
echo $3
}
myFunction "firstString" "second string with spaces" "thirdString"
When run, the output I'd expect is:
firstString
second string with spaces
thirdString
However, what's actually output is:
firstString
second
string
Is there a way to pass a string with spaces as a single argument to a function in Bash?
You should add quotes and also, your function declaration is wrong.
myFunction()
{
echo "$1"
echo "$2"
echo "$3"
}
And like the others, it works for me as well.
Another solution to the issue above is to set each string to a variable, call the function with variables denoted by a literal dollar sign \$. Then in the function use eval to read the variable and output as expected.
#!/usr/bin/ksh
myFunction()
{
eval string1="$1"
eval string2="$2"
eval string3="$3"
echo "string1 = ${string1}"
echo "string2 = ${string2}"
echo "string3 = ${string3}"
}
var1="firstString"
var2="second string with spaces"
var3="thirdString"
myFunction "\${var1}" "\${var2}" "\${var3}"
exit 0
Output is then:
string1 = firstString
string2 = second string with spaces
string3 = thirdString
In trying to solve a similar problem to this, I was running into the issue of UNIX thinking my variables were space delimeted. I was trying to pass a pipe delimited string to a function using awk to set a series of variables later used to create a report. I initially tried the solution posted by ghostdog74 but could not get it to work as not all of my parameters were being passed in quotes. After adding double-quotes to each parameter it then began to function as expected.
Below is the before state of my code and fully functioning after state.
Before - Non Functioning Code
#!/usr/bin/ksh
#*******************************************************************************
# Setup Function To Extract Each Field For The Error Report
#*******************************************************************************
getField(){
detailedString="$1"
fieldNumber=$2
# Retrieves Column ${fieldNumber} From The Pipe Delimited ${detailedString}
# And Strips Leading And Trailing Spaces
echo ${detailedString} | awk -F '|' -v VAR=${fieldNumber} '{ print $VAR }' | sed 's/^[ \t]*//;s/[ \t]*$//'
}
while read LINE
do
var1="$LINE"
# Below Does Not Work Since There Are Not Quotes Around The 3
iputId=$(getField "${var1}" 3)
done<${someFile}
exit 0
After - Functioning Code
#!/usr/bin/ksh
#*******************************************************************************
# Setup Function To Extract Each Field For The Report
#*******************************************************************************
getField(){
detailedString="$1"
fieldNumber=$2
# Retrieves Column ${fieldNumber} From The Pipe Delimited ${detailedString}
# And Strips Leading And Trailing Spaces
echo ${detailedString} | awk -F '|' -v VAR=${fieldNumber} '{ print $VAR }' | sed 's/^[ \t]*//;s/[ \t]*$//'
}
while read LINE
do
var1="$LINE"
# Below Now Works As There Are Quotes Around The 3
iputId=$(getField "${var1}" "3")
done<${someFile}
exit 0
A more dynamic way would be:
function myFunction {
for i in "$*"; do echo "$i"; done;
}
The simplest solution to this problem is that you just need to use \" for space separated arguments when running a shell script:
#!/bin/bash
myFunction() {
echo $1
echo $2
echo $3
}
myFunction "firstString" "\"Hello World\"" "thirdString"
Your definition of myFunction is wrong. It should be:
myFunction()
{
# same as before
}
or:
function myFunction
{
# same as before
}
Anyway, it looks fine and works fine for me on Bash 3.2.48.
Simple solution that worked for me -- quoted $#
Test(){
set -x
grep "$#" /etc/hosts
set +x
}
Test -i "3 rb"
+ grep -i '3 rb' /etc/hosts
I could verify the actual grep command (thanks to set -x).
You could have an extension of this problem in case of your initial text was set into a string type variable, for example:
function status(){
if [ $1 != "stopped" ]; then
artist="ABC";
track="CDE";
album="DEF";
status_message="The current track is $track at $album by $artist";
echo $status_message;
read_status $1 "$status_message";
fi
}
function read_status(){
if [ $1 != "playing" ]; then
echo $2
fi
}
In this case if you don't pass the status_message variable forward as string (surrounded by "") it will be split in a mount of different arguments.
"$variable": The current track is CDE at DEF by ABC
$variable: The
I had the same kind of problem and in fact the problem was not the function nor the function call, but what I passed as arguments to the function.
The function was called from the body of the script - the 'main' - so I passed "st1 a b" "st2 c d" "st3 e f" from the command line and passed it over to the function using myFunction $*
The $* causes the problem as it expands into a set of characters which will be interpreted in the call to the function using whitespace as a delimiter.
The solution was to change the call to the function in explicit argument handling from the 'main' towards the function: the call would then be myFunction "$1" "$2" "$3" which will preserve the whitespace inside strings as the quotes will delimit the arguments...
So if a parameter can contain spaces, it should be handled explicitly throughout all calls of functions.
As this may be the reason for long searches to problems, it may be wise never to use $* to pass arguments...

Resources