Bash array as argument inside of screen - arrays

The below code is is not working as I expect it to. I might be because I am doing this all wrong but I think it may be a quoting issue.
#!/bin/bash
IFS=$'\n'
fortune_lines=($(fortune | fold -w 30))
Screen_Session=$(mainscreen)
Screen_OneLiner=$(screen -p 0 -S ${Screen_Session} -X stuff "`printf "say ${fortune_lines[#]}\r"`")
for var in "${Screen_OneLiner[#]}"
do
echo "${var}"
done
I think I am not quoting something correctly because when I attempt to execute this. I get..
line 5: mainscreen: command not found
[screen is terminating
Essentially I am attempting to add this function (that works)
IFS=$'\n'
fortune_lines=($(fortune | fold -w 30))
To this screen one liner
screen -p 0 -S ${Screen_Session} -X stuff "`printf "say ${fortune_lines[#]}\r"`"
Then have it loop the array
for var in "${ArrayName[#]}"
do
echo "${var}"
done
So I am not sure how far I am away (in code) to what I am trying to do. Any help would be great.

Since feature requests to mark a comment as an answer remain declined, I copy the above solution here.
I managed to get this to work... gist.github.com/4006586 – user1787331

This line is problematic
Screen_Session=$(mainscreen)
You are using command substitution here, so if mainscreen is not a valid command, you'll get command not found error.
Maybe you mean to use braces instead of parentheses?

Related

Why does "echo $array" print all members of the array in this specific case instead of only the first member like in any other case?

I have encountered a very curious problem, while trying to learn bash.
Usually trying to print an echo by simply parsing the variable name like this only outputs the first member Hello.
#!/bin/bash
declare -a test
test[0]="Hello"
test[1]="World"
echo $test # Only prints "Hello"
BUT, for some reason this piece of code prints out ALL members of the given array.
#!/bin/bash
declare -a files
counter=0
for file in "./*"
do
files[$counter]=$file
let $((counter++))
done
echo $files # prints "./file1 ./file2 ./file3" and so on
And I can't seem to wrap my head around it on why it outputs the whole array instead of only the first member. I think it has something to do with my usage of the foreach-loop, but I was unable to find any concrete answer. It's driving me crazy!
Please send help!
When you quoted the pattern, you only created a single entry in your array:
$ declare -p files
declare -a files=([0]="./*")
If you had quoted the parameter expansion, you would see
$ echo "$files"
./*
Without the quotes, the expansion is subject to pathname generation, so echo receives multiple arguments, each of which is printed.
To build the array you expected, drop the quotes around the pattern. The results of pathname generation are not subject to further word-splitting (or recursive pathname generation), so no quotes would be needed.
for file in ./*
do
...
done

translation from bash to ash shell: how to handle arrays defined by input?

I try to transfer the excellent example docker-haproxy from centos to alpine.
A shell script is used to process a list of values given as parameters to the script into an array, then write these values plus their index to some file.
The following construction works in bash:
ServerArray=${SERVERS:=$1}
...
for i in ${ServerArray[#]}
do
echo " " server SERVER_$COUNT $i >> /haproxy/haproxy.cfg
let "COUNT += 1"
done
but not in ash (or sh):
syntax error: bad substitution
The error refers to line
for i in ${ServerArray[#]}
What is the correct syntax here? I guess the line
ServerArray=${SERVERS:=$1}
does not define an array as intended, but googling for long did not help me.
bash to sh (ash) spoofing says
sh apparently has no arrays.
If so, how to solve the problem then?
I guess I can do with this construction:
#!/bin/sh
# test.sh
while [ $# -gt 0 ]
do
echo $1
shift
done
delivers
/ # ./test 172.17.0.2:3306 172.17.0.3:3306
172.17.0.2:3306
172.17.0.3:3306
which is what I need to proceed

Having issues using IFS to cut a string into an array. BASH

I have tried everything I can think of to cut this into separate elements for my array but I am struggling..
Here is what I am trying to do..
(This command just rips out the IP addresses on the first element returned )
$ IFS=$"\n"
$ aaa=( $(netstat -nr | grep -v '^0.0.0.0' | grep -v 'eth' | grep "UGH" | sed 's/ .*//') )
$ echo "${#aaa[#]}"
1
$ echo "${aaa[0]}"
4.4.4.4
5.5.5.5
This shows more than one value when I am looking for the array to separate 4.4.4.4 into ${aaa[0]} and 5.5.5.5 into ${aaa[1]}
I have tried:
IFS="\n"
IFS=$"\n"
IFS=" "
Very confused as I have been working with arrays a lot recently and have never ran into this particular issue.
Can someone tell me what I am doing wrong?
There is a very good example on how to use IFS + read -a to split a string into an array on this other stackoverflow page
How does splitting string to array by 'read' with IFS word separator in bash generated extra space element?
netstat is deprecated, replaced by ss, so I'm not sure how to reproduce your exact problem

How can I make an array from curling a website?

How can I make an array from a link?
I am trying to do it with:
IFS=$'\n'
array=($(curl http://www.site.com))
but I keep getting a syntax error
You have:
array=(($curl http://www.site.com))
^^
Move the $ slightly:
$ array=($(curl http://www.example.com))
^
$ echo ${array[3]}
<title>Example Domain</title>
You are using BASH arrays here. A common issue is that you're shebang is still pointing to the POSIX sh. The old POSIX sh doesn't support arrays. Make sure the top line of your file looks like this:
#!/bin/bash

is it possible to use bash to access more than one array in a for loop

I'm trying to write a bash script that will let me download multiple web pages using curl. For each webpage, I want to be able to pass curl the page and the referer link. I want to be able to supply multiple webpages at once.
In other words, I want to be able to loop through the webpages I supply the script, and for each page, pass the associated webpage and referer link to curl.
I thought I'd use an array to store the webpage and referer link in a single variable, thinking that I could then extract the individual elements of the array when running curl.
My problem is that I can't figure out how to get multiple arrays to work properly in a for loop. Here is an idea of what I want to do. This code does not work, since "$i" (in the for loop) doesn't become an array.
#every array has the information for a separate webpage
array=( "webpage" "referer" )
array2=( "another webpage" "another referer" )
for i in "${array[#]}" "${array2[#]}" #line up multiple web pages
do
#use curl to download the page, giving the referer ("-e")
curl -O -e "${i[1]}" "${i[0]}"
done
If I was only working with one array, I could easily do it like this:
array=( "webpage" "referer" )
REFERER="${array[1]}"
PAGE="${array[0]}"
#use curl to download the page, giving the referer ("-e")
curl -O -e "$REFERER" "$LINK"
It's once I have more than one webpage that I want to process at once that I can't figure out how to do it correctly.
If there is another way to handle multiple webpages, without having to use arrays and a for loop, please let me know.
If there is another way to handle multiple webpages, without having to use arrays and a for loop, please let me know.
Using arrays is fine, at least it's much better than using space-separated lists or similar hacks. Simply loop over the indices:
array=('webpage' 'another webpage')
array2=('referrer' 'another referrer')
# note the different layout!
for i in "${!array[#]}"
do
webpage="${array[$i]}"
referrer="${array2[$i]}"
done
You need a trick here. Note that spaces are not allowed in URLs, so you can say:
webpages=("url referrer" "url2 ref2" ...)
for i in "${webpages[#]}" ; do
set -- "$i"
url="$1"
ref="$2"
curl -O -e "${url}" "${ref}"
done
[EDIT] Maybe a better solution will be to put all the URLs into a file and then use this code:
while read url ref ; do
curl -O -e "${url}" "${ref}"
done < file
or if you prefer here documents:
while read url ref ; do
echo "url=$url ref=$ref"
done <<EOF
url1 ref1
url2 ref2
... xxx
EOF
Just as a general aside: Inside a function at least just declare the IFS variable to limit its scope to that function only. No need to save & restore IFS via OLD_IFS!
help declare
IFS=$' \t\n'
printf "%q\n" "$IFS"
function ifs_test () {
declare IFS
IFS=$'\n'
printf "%q\n" "$IFS"
return 0
}
ifs_test
printf "%q\n" "$IFS"
Thanks to everyone for their responses. Both ideas had merit, but I found some code in the Advanced Bash Guide that does exactly what I want to do.
I can't say I fully understand it, but by using an indirect reference to the array, I can use multiple arrays in the for loop. I'm not sure what the local command does, but it is the key (I think it runs a sort of eval and assigns the string to the variable).
The advantage of this is that I can group each webpage and referer into their own array. I can then easily add a new website, by creating a new array and adding it to the for loop. Also, should I need to add more variables to the curl command (such as a cookie), I can easily expand the array.
function get_page () {
OLD_IFS="$IFS"
IFS=$'\n' # If the element has spaces, when using
# local to assign variables
local ${!1}
# Print variable
echo First Variable: "\"$a\""
echo Second Variable: "\"$b\""
echo ---------------
echo curl -O -e "\"$a\"" "\"$b\""
echo
IFS="$OLD_IFS"
}
#notice the addition of "a=" and "b="
#this is not an associative array, that would be [a]= and [b]=
array=( a="webpage" b="referer" )
array2=( a="another webpage" b="another referer" )
#This is just a regular string in the for loop, it doesn't mean anything
#until the indirect referencing later
for i in "array[*]" "array2[*]" #line up multiple web pages
do
#must use a function so that the local command works
#but I'm sure there's a way to do the same thing without using local
get_page "$i"
done
This results in:
First Variable: "webpage"
Second Variable: "referer"
---------------
curl -O -e "webpage" "referer"
First Variable: "another webpage"
Second Variable: "another referer"
---------------
curl -O -e "another webpage" "another referer"

Resources