How to pass one argument into multiple arrays - arrays

I want my bash script to process one or multiple attachments. They're passed to the script by the following parameter:
--attachment "filename(1),pathtofile(1),fileextension(1);[...];filename(n),pathtofile(n),fileextesion(n)"
--attachment "hello,/dir/hello.pdf,pdf;image,/dir/image.png,png"
This argument is stored in inputAttachments.
How can I store them in the following array?
attachmentFilename=("hello" "image")
attachmentPath=("/dir/hello.pdf" "/dir/image.png")
attachmentType=("pdf" "png")
My thought: I need to seperate inputAttachments at every semicolon and split those parts again at the comma. But how is this done and passed into the array.

I'm not exactly sure, how you are capturing the string after --attachment argument. But once you have it in a shell variable, all you need is a two-pass split which you can accomplish in the bash shell using read and a custom de-limiter to split on by setting the IFS value
IFS=\; read -r -a attachments <<<"hello,/dir/hello.pdf,pdf;image,/dir/image.png,png"
With this the string is split on ; and stored in the array attachments as individual elements which you can visualize by doing declare -p on the array name
declare -p attachments
declare -a attachments='([0]="hello,/dir/hello.pdf,pdf" [1]="image,/dir/image.png,png")'
Now loop over the array and re-split the elements on , and append to individual arrays
for attachment in "${attachments[#]}"; do
IFS=, read -r name path type <<<"$attachment"
attachmentFilename+=( "$name" )
attachmentPath+=( "$path" )
attachmentType+=( "$type" )
done

Related

Split comma separated and quoted string into an array in Bash

I need to split a comma separated, but quoted list of strings into an indexed bash array in a script.
I know there are a lot of posts on the web in general and also on SO that show how to create an indexed array from a given line / string, but I could not find any example that does the array elements the way I need. I apologise, if I have missed any obvious examples from SO itself.
I am reading a file that I receive from someone, and cannot change it.
The file is formatted like this
"Grant ACL","grantacls.sh"
"Revoke ACL","revokeacls.sh"
"Get ACls for Topic","topicacls.sh"
"Get Topics for User with ACLs","useracls.sh"
I need to create an array for each line above where the separator is comma - and each of the quoted string will be an array element. I have tried various options. The latest attempt was using a construct like this - copied from some example on the web
parseScriptMapLine=${scriptName[$IN_OPTION]}
mapfile -td ',' script1 < <(echo -n "${parseScriptMapLine//, /,}")
declare -p script1
echo "script1 $script1"
where script name is an associative array created from the original file, whose format is with 1, 2, etc. as the key and the other part after '=' sign as value.
The above snippet prints
script1
And the value part I need to split into an indexed array, so that I can pass the second element as a parameter. When creating indexed array from the value string, if I have to lose the quotes, that is fine or if it creates the elements with the quotes, that is fine too.
1="Grant ACL","grantacls.sh"
2="Revoke ACL","revokeacls.sh"
3="Get ACls for Topic","topicacls.sh"
4="Get Topics for User with ACLs","useracls.sh"
I have looked at a lot of examples, but haven't been able to get this particular requirement working.
Thank you
With apologies, I could not understand what you wanted - this sounds like an X/Y Problem. Can you clarify?
Maybe this?
$: while IFS=',"' read -r _ a _ _ d _ && [[ -n "$d" ]]; do echo "a=[$a] d=[$d]"; done < file
a=[Grant ACL] d=[grantacls.sh]
a=[Revoke ACL] d=[revokeacls.sh]
a=[Get ACls for Topic] d=[topicacls.sh]
a=[Get Topics for User with ACLs] d=[useracls.sh]
That will let you do whatever you wanted with the fields, which I named a and d.
If you just want to load the lines of the file into an array -
$: mapfile -t script1 < file
$: for i in "${!script1[#]}"; do echo "$i=${script1[i]}"; done
0="Grant ACL","grantacls.sh"
1="Revoke ACL","revokeacls.sh"
2="Get ACls for Topic","topicacls.sh"
3="Get Topics for User with ACLs","useracls.sh"
If you want a two-dimensional array, then sorry, you're going to have to use something besides bash. or get more creative.

How to copy an array to a new array with dynamic name?

I have a complex data structure in Bash like this:
Test1_Name="test 1"
Test1_Files=(
file01.txt
file02.txt
)
Test2_Name="test 2"
Test2_Files=(
file11.txt
file12.txt
)
TestNames="Test1 Test2"
In my improved script, I would like read the files from disk. Each test resides in a directory.
So I have a Bash snippet reading directories and reading all the file names. The result is present in an array: $Files[*].
How can I copy that array to an array prefixed with the test's name. Let's assume $TestName holds the test's name.
I know how to create a dynamically named array:
for $Name in $TestNames; do
declare -a "${TestName}_Files"
done
Will create e.g. Test1_Files and Test2_Files. The variables are of type array, because I used -a in declare.
But how can I copy $Files[*] to "${TestName}_Files" in such a loop?
I tried this:
declare -a "${TestName}_Files"=${Files[*]}
But it gives an error that =file01.txt is not a valid identifier.
You'll want to use newarray=( "${oldarray[#]}" ) to keep the array elements intact. ${oldarray[*]} will involve word splitting, which will break at least with elements containing white space.
However, the obvious declare -a "$name"=("${oldarray[#]}") doesn't work, with the parenthesis quoted or not. One way to do it seems to be to use a name ref. This would copy the contents of old to new, where the name of new can be given dynamically:
#!/bin/bash
old=("abc" "white space")
name=new
declare -a "$name" # declare the new array, make 'ref' point to it
declare -n ref="$name"
ref=( "${old[#]}" ) # copy
#unset -n ref # unset the nameref, if required
declare -p "$name" # verify results

How can I qsub a bash script in a job array varying its parameters stored in a array in bash

I have a script which I want to execute with several different arguments, I've got an array that contains all the parameter(argument) combinations ${array[i]}.
I want to be able to submit a job array using all the different argument stored in the array:
arr_length=${#submittions[#]}
qsub -t 1-$arr_length myscript <*>
*Here, I want to use the values of -t to go through my array and use the different parameters stored in it here, I don't know is it is possible.
I have read that there is a built in variable $SGE_TASK_ID.
The array contain from two to seven file paths separated by one space and an amount of arr_length elements in the array. which will be the arguments for the python script.
${!array[#]} never contains the values of the elements in the array. The contain only the indices. For the array elements use "${array[#]}" in your script as
qsub -t 1-${arr_length} myscript "${array[#]}"
E.g.
array=('foo' 'bar' 'dude')
printf '%s\n' "${!array[#]}"
0
1
2
and see the output of
printf '%s\n' "${array[#]}"

Splitting string separated by comma into array values in shell script?

My data set(data.txt) looks like this [imageID,sessionID,height1,height2,x,y,crop]:
1,0c66824bfbba50ee715658c4e1aeacf6fda7e7ff,1296,4234,194,1536,0
2,0c66824bfbba50ee715658c4e1aeacf6fda7e7ff,1296,4234,194,1536,0
3,0c66824bfbba50ee715658c4e1aeacf6fda7e7ff,1296,4234,194,1536,0
4,0c66824bfbba50ee715658c4e1aeacf6fda7e7ff,1296,4234,194,1536,950
These are a set of values which I wish to use. I'm new to shell script :) I read the file line by line like this ,
cat $FILENAME | while read LINE
do
string=($LINE)
# PROCESSING THE STRING
done
Now, in the code above, after getting the string, I wish to do the following :
1. Split the string into comma separated values.
2. Store these variables into arrays like imageID[],sessionID[].
I need to access these values for doing image processing using imagemagick.
However, I'm not able to perform the above steps correctly
set -A doesn't work for me (probably due to older BASH on OSX)
Posting an alternate solution using read -a in case someone needs it:
# init all your individual arrays here
imageId=(); sessionId=();
while IFS=, read -ra arr; do
imageId+=(${arr[0]})
sessionId+=(${arr[1]})
done < input.csv
# Print your arrays
echo "${imageId[#]}"
echo "${sessionId[#]}"
oIFS="$IFS"; IFS=','
set -A str $string
IFS="$oIFS"
echo "${str[0]}";
echo "${str[1]}";
echo "${str[2]}";
you can split and store like this
have a look here for more on Unix arrays.

Passing An Array From One Bash Script to Another

I am new to writing Shell Scripts and am having some difficulties.
What I Want To Achieve
I have an array of strings in scriptOne.sh that I want to pass to scriptTwo.sh
What I Have Done So Far
I can execute the second script from inside the first using ./scriptTwo.sh and I have passed string variables from one to the other using ./scriptTwo.sh $variableOne.
The issues are when I try to pass an array variable it doesn't get passed. I have managed to get it to pass the first entry of the array using ./scriptTwo.sh "${array[#]}" however this is only one of the entries and I need all of them.
Thanks in advance for your help
Your way of passing the array is correct
./scriptTwo.sh "${array[#]}"
The problem is probably in the way how you receive it. In scriptTwo.sh, use
array=("$#")
I think we can directly read the array content from sriptOne.sh if you use a declare command.
I declare an Associative array named wes_batch_array in scriptOne.sh and I want to pass it to scriptTwo.sh so I put the command below in scriptTwo.sh:
declare -A wes_batch_array=$(awk -F '=' '{if ($1 ~ /^declare -A wes_batch_array/) {for (i=2;i<NF;i++) {printf $i"=";} printf $NF"\n";}}' < scriptOne.sh)
I've tested this command and it works fine.
If you do not use the declare command. You can echo the content of array to another middle temp file and use the awk command above to grab the content of bash array.
The way I solved this problem was to step through the array in script1.sh, then pass the array elements to script2.sh using a for loop. In my case I was passing many arrays with varying numbers of elements to the same script2.sh on different servers.
So for example:
script1.sh:
records="111111111 222222222 333333333"
myRecordsArray=($records)
for (( i=0 ; i < $(#myRecordsArray[#]} ; i++ )); do
./script2.sh ${myRecordsArray[i]}
done
script2.sh:
main () {
<some code here>
}
myRecord=$1
main $myRecord

Resources