Change values of array that is a copy of argument array - arrays

I am trying to change the values inside an array that is a copy of arguments array ("$#"). Let's say I execute the script as follows: $ sh script.sh 1 2 3
This is the script:
list="$#"
echo ${list[*]}
list[1]=4
echo ${list[*]}
Expected output:
1 2 3
1 4 3
What I actually get:
1 2 3
1 2 3 4
Any idea what causes this behavior and how can I fix it?

list="$#" sets list to a plain variable, not an array. Use list=("$#") to store it as an array instead. BTW, you should generally use "${list[#]}" to get the elements of an array, instead of ${list[*]} to avoid problems with whitespace in elements, wildcards getting expanded to lists of matching files, etc.
In general, this is the proper way to copy an array:
copyarray=("${oldarray[#]}")

Just found this answer. Command line arguments array is not quite a normal array and has to be converted to an actual array first as follows:
list=("$#")

Related

How to assign the # array to another variable in bash?

Amongst the answers to How to copy an array in Bash?, the solution for copying an array from one variable to another is arrayClone=("${oldArray[#]}").
However, what if the array I need to copy is the list of arguments, #?
A simple test script like:
#! /bin/bash
argsCopy=("${#[#]}")
Fails with an error:
line 3: ${#[#]}: bad substitution
By way of experimentation, it appears that argsCopy=("$#") is sufficient.
When I run the following via ./test.sh 1 2 3\ 4,
#! /bin/bash
set -x
argsCopy=("$#")
echo "${argsCopy[#]}" > /dev/null
it outputs:
+ argsCopy=("$#")
+ echo 1 2 '3 4'
However, like many things in sh/bash, I can't explain what rules of the language cause this to work, or under what circumstances it might end up failing.

How can I pass an array as argument to an R script command line run?

I'm trying to pass an array of hundreds of elements as an argument of an R script via command line in Windows. Firstly, I'd like to declare my array in some way. I'm doing that in command line:
set my_array=c(0,1,2,3,4,5,6,7,8,9,...,700)
Then I want to run my script and get the array as argument.
Rscript my_script my_array
But when I try this an error message came up saying that 'the object my_array" could not be found. I know how to get the arguments in my script, using args <- commandArgs(TRUE). I just need to recognize my declared array as an argument - or declare it in the right way and pass it in the right way as an argument to my script.
Thanks!
First, i am not sure if you should use set to declare any variable in terminal, but you can see more of this on man set page.
There are some ways i think you can try to pass an array to R script, it mainly depends on how you declare the my_array in terminal.
1 - "my_array" can be a string in bash:
$ my_array="c(0,1,2,3,4)"
$ Rscript my_script ${my_array}
And use the eval(parse(text=())) in R script to transform the argument as a vector to R environment.
args <- commandArgs(trailingOnly=TRUE)
print(args)
# c(0,1,2,3,4,5,6,7,8,9)
args <- eval(parse(text=args[1]))
print(args)
# [1] 0 1 2 3 4 5 6 7 8 9
2 - "my_array" can be an array in bash:
$ my_array=(0,1,2,3,4)
$ Rscript my_script ${my_array[*]}
and in R the args is already your array, but of type character:
args <- commandArgs(trailingOnly=TRUE)
print(args)
# [1] "0" "1" "2" "3" "4" "5"
I think I understand what you're trying to do here, let me know if I'm wrong.
I created an R script (called script.R) that contains the following:
args <- commandArgs(TRUE)
eval(parse(text=args[1]))
print(myarray)
I can then call the script like this (from my command line)
Rscript script.R myarray="c(1,3,4)"
As you can see, the argument gets passed (in your script you could do print(args) to see what gets passed and how), I use eval(parse(text=...))) to make it execute (create myarray in the script) and then I can do what I want with it (in my case, I printed it, but you could do analysis or other stuff). Does this help?
If you have hundreds of values in the array, perhaps it'd more useful to write it to a text file and pass the file path as a parameter and have R read it in.

bash script to dynamically display array element based on user selection(s)

i have to task to write a bash script which can let user to choose which array element(s) to display.
for example, the array have these element
ARRAY=(zero one two three four five six)
i want the script to be able to print out the element after user enter the array index
let say the user entered(in one line) : 1 2 6 5
then the output will be : one two six five
the index entered can be single(input: 0 output: zero) or multiple(such as above) and the output will be correspond to the index(es) entered
any help is much appreciated.
thanks
ARRAY=(zero one two three four five six)
for i in $#; do
echo -n ${ARRAY[$i]}
done
echo
Then call this script like this:
script.sh 1 2 6 5
it will print:
one two six five
You would want to use associative arrays for a generic solution, i.e. assuming your keys aren't just integers:
# syntax for declaring an associative array
declare -A myArray
# to quickly assign key value store
myArray=([1]=one [2]=two [3]=three)
# or to assign them one by one
myArray[4]='four'
# you can use strings as key values
myArray[five]=5
# Using them is straightforward
echo ${myArray[3]} # three
# Assuming input in $#
for i in 1 2 3 4 five; do
echo -n ${myArray[$i]}
done
# one two three four 5
Also, make sure you're using Bash4 (version 3 doesn't support it). See this answer and comment for more details.

Pass array to function name collision

Specs
GNU bash, version 3.1.17 (No possibility of upgrade)
Premise
I've been messing around with arrays and i was wondering if there is any way to have a variable local to a function with the same name as an array outside of said function.
Example
In the below examples I will try to display the issue
Working
#!/bin/bash
arr=(1 2 "3 4" 5) # Make global array
myfunc()
{
local args=("${!1}") # Using different name for declaration
echo ${args[#]} # Echo new array
}
myfunc arr[#] # Pass array to function
Output
1 2 3 4 5
Not working
#!/bin/bash
arr=(1 2 "3 4" 5) # Create array
myfunc()
{
local arr=("${!1}") #Not working
echo ${arr[#]} # Not working
}
myfunc arr[#] # Pass array to function
Output
[Blank]
Reason
I want to pass multiple arrays to the function but do not want to have a possible name collision with the array being passed in and the local array name.
Tried
As you can see above i have tried adding the local function. I've scanned the bash man page and cannot seem to find anything else that could provide the behaviour i desisre
Bash -x Results
+ arr=(1 2 "3 4" 5)
+ myfunc 'arr[#]'
+ arr=("${!1}")
+ local arr
+ echo
If any more information is needed then please let me know.
Congratulations you've hit a bug in the 3.1 series of bash.
From the Bash ChangeLog in the section relating to the bash-3.2-alpha release:
This document details the changes between this version, bash-3.2-alpha,
and the previous version, bash-3.1-release.
...
f. Fixed two bugs with local array variable creation when shadowing a variable
of the same name from a previous context.

In bash, is it possible to put several arrays inside quotes and then access them?

I know I can do this:
set=("1 2 3" "4 5 6")
for subset in "${set[#]}"
do
for element in $subset
do
echo $element
done
done
1 2 3 4 5 6 will be printed sequentially. However, I can not do this:
set="(1 2 3) (4 5 6)"
for subset in $set
do
echo ${subset[2]}
done
I want to print 3 6. The reason why I want to do this is that I want to have access to whichever element I want to access during iteration instead of iterating one by one. That's why I try to put arrays inside quotes instead of putting quotes inside a big array. Is there any way to do this?
Thanks,
Unfortunately, I don't think bash supports multi-dimentional arrays, which sounds like what you're looking for. You can simulate it with a little help from bash itself like so:
x=()
x+=("1,2,3")
x+=("4,5,6")
for val in ${x[#]}; do
subset=($(echo $val | tr ',' ' '))
echo ${subset[2]}
done

Resources