I'm almost completely new to Linux programming, and Bash Scripts. I build an amateur radio AllStar node.
I'm trying to create a script that looks at a certain variable and based on that info decides if it should connect or not. I can use a command: asterisk -rx "rpt showvars 47168. This returns a list of variables and their current values. I can store the whole list into a variable that I define, in my test script I just called it MYVAR but I can't seem to only get the value of one of the variables that's listed.
I talked to someone who knows a lot about Linux programming, and she suggested that I try CONNECTED="${MYVAR[3]}" but when I do this, CONNECTED just seems to become a blank variable.
What really frustrates me is I have written programs in other programming languages, and I've been told Bash scripts are easy to learn, but yet I can't seem to get this.
So any help would be great.
how did you assigned your variable?
It seems to me that you want to work with an array, then:
#!/bin/bash
myvar=( $( asterisk -rx "rpt showvars 47168 ) )
echo ${mywar[3]} # this is your fourth element
echo ${#myvar[#]} # this is the total of element in your array
be careful that index in an array starts at 0
Related
I am currently working on a small command line interface tool that someone not very familiar with bash could run from their computer. I have changed content for confidentiality, however functionality has remained the same.
The user would be given a prompt
the user would then respond with their answer(s)
From this, I would be given two bits of information:
1.their responses now as individual variables
2.the number of variables that I have now been given: this value is now a variable as well
my current script is as follows
echo List your favorite car manufacturers
read $car1 $car2 $car3 #end user can list as many as they wish
for n in {1..$numberofmanufacturers} #finding the number of
variables/manufactures is my second question
do
echo car$n
done
I am wanting to allow for the user to enter as many car manufacturers as they please (1=<n), however I need each manufacturer to be a different variable. I also need to be able to automate the count of the number of manufacturers and have that value be its own new variable.
Would I be better suited for having the end user create a .txt file in which they list (vertically) their manufactures, thus forcing me to use wc -l to determine the number of manufacturers?
I appreciate any help in advance.
As I said in the comment, whenever you want to use multiple dynamically created variables, you should check if there isn't a better data structure for your use case; and in almost all cases there will be. Here is the implementation using bash arrays. It prints out the contents of the input array in three different ways.
echo List your favorite car manufacturers
# read in an array, split on spaces
read -a cars
echo Looping over array values
for car in "${cars[#]}"
do
echo $car
done
echo Looping over array indices
for i in ${!cars[#]}
do
echo ${cars[$i]}
done
echo Looping from 0 to length-1
let numcars=${#cars[#]}
for i in $(seq 0 $((numcars-1)))
do
echo ${cars[$i]}
done
I have defined a variable inside one of the shell script to create the file name with date value in it.
I used "date +%Y%m%d" command to insert the current date which was defined in date_val variable.
And I have defined the filename variable to have "${path}/sample_${date_val}.txt
For few days it was creating the file name properly as /programfiles/sample_20180308.txt
But today the filename was created without date as /programfiles/sample_.txt
When I try to execute the command "date +%Y%m%d" in linux, it is returning the correct value - 20180309.
Any idea why the filename was created without the date value ??? . I did not modify anything in my script too. So wondering what might have gone wrong.
Sample excerpt of my script is given below for easy understanding :
EDITED
path=/programfiles
date_val=$(date +%Y%m%d )
file_name=${path}/sample_${date_val}.txt
Although incredibly unlikely, it's certainly possible for date to fail, based on the source code. Under the covers, it calls either clock_gettime() or gettimeofday(), both of which can fail.
The date program will also refuse to output anything to standard output if the date from either of those two functions is out of range during the call to (which is possible if they fail).
It's also possible that the date program could "disappear" for various reasons, such as actually being hidden or permissions changed, or a shortage of resources like file handles when attempting to open the executable.
As mentioned, all these possibilities are a stretch, unlikely to happen in the real world.
If you want to handle the case where you get inadequate output from date, you can simply try until you get a valid one, something like (with the possibility of adding some limit to detect if it's never any good):
todaysDate="$(date +%Y%m%d)"
while [[ ! $x =~ ^[0-9]{8}$ ]] ; do
sleep 1
todaysDate="$(date +%Y%m%d)"
done
# todaysDate now guaranteed to be eight digits.
I'm working with a growing bash script and within this script I have a number of functions. One of these functions is supposed to return a variables value, but I am running into some issues with the syntax. Below is an example of the code.
ShowTags() {
local tag=0
read tag
echo "$tag"
}
selected_tag=$(ShowTags)
echo "$selected_tag"
pulled this code from a Linux Journal article, but the problem is it doesn't seem to work, or perhaps it does and im missing something. Essentially whenever the function is called the script hangs up and does not output anything, I need to CTRL+C to drop back to CLI.
The article in question is below.
http://www.linuxjournal.com/content/return-values-bash-functions
So my question is this the proper way to return a value? Is there a better or more dependable way of doing this? And if there is please give me an example so I can figure this out without using global variables.
EDIT:
The behavior of this is really getting to me now. I am using the following script.
ShowTags() {
echo "hi"
local tag=0
read tag
echo "$tag"
}
selected_tag=$(ShowTags)
echo "$selected_tag
Basically what happens is bash will act as if the read command is taking place before the echo tag at the top of the function. As soon as I pass something to read though it will run the top echo, and complete the rest of the script. I am not sure why this is happening. This is exactly what is happening in my main script.
Change echo "hi" to echo "hi" >/dev/tty.
The reason you're not seeing it immediately is that $(ShowTags) captures all the standard output of the function, and that gets assigned to selected_tag. So you don't see any of it until you echo that variable.
By redirecting the prompt to /dev/tty, it's always displayed immediately on the terminal, not sent to the function's stdout, so it doesn't get captured by the command substitution.
You are trying to define a function with Name { ... ]. You have to use name() { ... }:
ShowTags() { # add ()
local tag=0
read tag
echo "$tag"
} # End with }
selected_tag=$(ShowTags)
echo "$selected_tag"
It now lets the user type in a string and have it written back:
$ bash myscript
hello world # <- my input
hello world # script's output
You can add a prompt with read -p "Enter tag: " tag to make it more obvious when to write your input.
As #thatotherguy pointed out, your function declaration syntax is off; but I suspect that's a transcription error, as if it was wrong in the script you'd get different problems. I think what's going on is that the read tag command in the function is trying to read a value from standard input (by default that's the terminal), and pausing until you type something in. I'm not sure what it's intended to do, but as written I'd expect it to pause indefinitely until something's typed in.
Solution: either type something in, or use something other than read. You could also add a prompt (read -p "Enter a tag: " tag) to make it more clear what's going on.
BTW, I have a couple of objections to the linux journal article you linked. These aren't relevant to your script, but things you should be aware of.
First, the function keyword is a nonstandard bashism, and I recommend against using it. myfunc() ... is sufficient to introduce a function definition.
Second, and more serious, the article recommends using eval in an unsafe way. Actually, it's really hard to use eval safely (see BashFAQ #48). You can improve it a great deal just by changing the quoting, and even more by not using eval at all:
eval $__resultvar="'$myresult'" # BAD, can evaluate parts of $myresult as executable code
eval $__resultvar='"$myresult"' # better, is only vulnerable to executing $__resultvar
declare $__resultvar="$myresult" # better still
See BashFAQ #6 for more options and discussion.
I am used to object oriented programming. Now, I have just started learning unix bash scripting via linux.
I have a unix script with me. I wanted to break it down into "modules" or preferably programs similar to "more", "ls", etc., and then use pipes to link all my programs together. E.g., "some input" myProg1 | myProg2 | myProg3.
I want to organize my code and make it look neater, instead of all in one script. Also, it will be easy to do testing and development.
Is it possible to do this, especially as a newbie ?
There are a few things you could take a look at, for example the usage of aliases in bash and storing them in either bashrc or a seperate file called by bashrc
that will make running commands easier..
take a look here for expanding commands into aliases (simple aliases are easy)
You can also look into using functions in your code (lots of bash scripts in above link's home folder to make sense of functions browse this site :) which has much better examples...
Take a look here for some piping tails into script
pipe tail output into another script
The thing with bash is its flexibility, so for example if something starts to get too messy for bash you could always write a perl/Java any lang and then call this from within your bash script, capture its output and do something else..
Unsure why all the pipes anyways here is something that may be of help:
./example.sh 20
function one starts with 20
In function 2 20 + 10 = 30
Function three returns 10 + 10 = 40
------------------------------------------------
------------------------------------------------
Local function variables global:
Result2: 30 - Result3: 40 - value2: 10 - value1: 20
The script:
example.sh
#!/bin/bash
input=$1;
source ./shared.sh
one
echo "------------------------------------------------"
echo "------------------------------------------------"
echo "Local function variables global:"
echo "Result2: $result2 - Result3: $result3 - value2: $value2 - value1: $value1"
shared.sh
function one() {
value1=$input
echo "function one starts with $value1"
two;
}
function two() {
value2=10;
result2=$(expr $value1 + $value2)
echo "In function 2 $value1 + $value2 = $result2"
three;
}
function three() {
local value3=10;
result3=$(expr $value2 + $result2;)
echo "Function three returns $value2 + $value3 = $result3"
}
I think the pipes you mean can actually be functions and each function can call one another.. and then you give the script the value which it passes through the functions..
bash is pretty flexible about passing values around, so long as the function being called before has the variable the next function being called by it can reuse it or it can be called from main program
I also split out the functions which can be sourced by another script to carry out the same functions
E2A Thanks for the upvote, I have also decided to include this link
http://tldp.org/LDP/abs/html/sample-bashrc.html
There is an awesome .bashrc to be reused, it has a lot of functions which will also give some insight into how to simplify a lot of daily repetitive commands such as that require piping, an alias can be written to do all of them for you..
You can do one thing.
Just as a C program can be divided into a header file and a source file for reducing complexity, you can divide your bash script into two scripts - a header and a main script but with some differences.
Header file - This will contain all the common variables defined and functions defined which will be used by your main script.
Your script - This will only contain function calls and other logic.You need to use "source <"header-file path">" in your script at starting to get all the functions and variables declared in the header available to your script.
Shell scripts have standard input and output like any other program on Unix, so you can use them in pipes. Splitting your scripts is a good solution because you can later use them in pipes with other commands.
I organize my Bash projects in the following way :
Each command is put in its own file
Reusable functions are kept in a library file which is just a classic script with only functions
All files are in the same directory, so commands can find the library with $(dirname $0)/library
Configuration is stored in another file as environment variables
To keep things clear, you should not use global variables to communicate between functions and main program.
I prepare a template for scripts with the following parts prepared :
Header with name and copyright
Read configuration with source
Load library with source
Check parameters
Function to display help, which is called if asked for or if parameters are wrong
My best advice is : always write the help function, as the next person who will need it is ... yourself !
To install your project you simply copy all files, and explain what to configure in the configuration file.
01) I am trying to use the && operator in a for loop as shown below in the script. However this does not seem to work. I was not able to see the error generated in the terminal window, since it closes as soon as it runs in to an error. Could someone please tell me what I'm doing wrong?
#!/bin/bash
cd ~/Documents/DTI/
#subj and subj1 contain folders which are located in the DTI directory
subj="ARN MT"
subj1="ARNpre1 ARNpre2"
for [[s in $subj] && [s1 in $subj1]]
02) And as you can see in my "subj1", the first two entries start with the letters ARN which means that they are sub directories of ARN(located in a different place.Not in ARN main directory). So I also want to run a command in which, if subj1 contains subj then it must perform a certain command.For this purpose I wrote the following,
if [[ ${s1} == *"${s}"* ]];then
would this be the right way to do such operation?
I would greatly appreciate any help.
Thank you in advance.
I think by for [[s in $subj] && [s1 in $subj1]] you mean this:
for s in $subj; do
for s1 in $subj1; do
# do something
done
done
By nesting the for loops you'll loop through every possible combination of s and s1, which sounds like what you're trying to do in part 1 of your question.
However, I can't make sense of what you're talking about in part 2, so I can't help you there.