How to modify a string of values in bash? - arrays

I have an array of strings. These strings contain values in the format of an (x,y) coordinate pair, e.g. string one contains "42,37", string two contains "54,17", and so forth. How can I modify this array of strings such that "42,37" becomes "+42+37", "54,17" becomes "+54+17", and so on?
I'm rather new to bash and writing a simple utility, I've racked my brain over this issue for the past day.

With bash, after the for loop new_array will contain your desired format.
a=("42,37" "54,17")
x=0
for i in "${a[#]}"; do
b=${a[$x]}
new_array[$x]="+${b:0:2}+${b:3:2}"
((x++))
done
Output:
for i in "${new_array[#]}"; do echo $i; done
+42+37
+54+17

Related

Using awk to parse a string from a file

I'm still learning Unix and I'm having issues understanding the following line of code.
echo "$lines" | awk '{split($0,a,":"); print a[3],a[2],a[1]}'
I don't understand what is happening with the array a in the line of code above. Is it declaring the array and setting it equal to the string it's parsing? If it is declaring the array a, then, why can't I print out the results later on in the code?
echo "${a[1]}"
The line above prints an empty line and not what has been stored in the array a when the string was parsed. I know there is always something in the string that needs to be parsed and when I call the array a[1] I know that I'm in inside the scope. I just don't see/understand what is happening with the array a that prevents me from printing it out later on in the code.
Your code is printing a line for each line of input. If you dont have get output, my first guess would be, that you don't have input.
Given an input of:
lines="ab:cd:ef
ij:kl:m"
the output is:
ef cd ab
m kl ij
awk is executing the commands (which is everything in between the single quotes) for each line of input. First splitting the input line $0 at each : into an array a, then printing the first three elements in reverse order.
If you try to access an array element in the shell, what echo suggests, then you are too late. The array exists within awk and is gone when awk has finished.

Passing an array as an argument from a Perl script to a R script

I am new to R and I have a Perl Script in which I want to call a R Script, which calculates something for me (not important what in this context). I want to give as arguments an input file, an array which contains some numbers and a number for a total number of clusters. medoid.r is the name of my R Script.
my $R_out;
$R_out = qx{./script/medoid.r $output #cluster $NUMBER_OF_CLUSTERS}
My current R code looks like this. Right now I just print cluster to see what is inside.
args <- commandArgs(TRUE)
filename = args[1]
cluster = as.vector(args[2])
number_of_cluster = args[3]
matrix = read.table(filename, sep='\t', header=TRUE, row.names=1, quote="")
print(cluster)
Is it possible to give an array as an argument? How can I save it in R? Right now only the first number of the array is stored and printed, but I would like to have every number in a vector or something similar.
If you do this in Perl
$R_out = qx{./script/medoid.r $output #cluster $NUMBER_OF_CLUSTERS};
your command line will look similar to this
./scriptmedoid.r output 111 222 333 3
assuming that $output is 'output' and #clusters = (111, 222, 333).
If you want to read that in R, you need to assign all elements after the first one in args to cluster but the last one, and the last one to number_of_cluster. In Perl you can use shift and pop for that.
my #args = #_;
my $output = shift #args;
my $number = pop #args;
# now #args only contains the clusters
I don't know if those operators exist in R.
You cannot pass a full data structure unless you serialize it in some way.
In perl, qx will expect a string as an argument. You may certainly use an array to generate that string, but ultimately it will still be a string. You cannot "pass an array" to a system call, you can only pass command-line text/arguments.
Keep in mind, you are executing a system call running Rscript as a child process. The way you're describing the issue, there is no inter-process communication beyond the command line. Think of it this way: how would you type an array on the command line? You may have some textual way of representing an array, but you can't type an array on the command line. Arrays are stored and accessed in memory differently by various different languages, and thus are not really portable between two languages like you're suggesting.
One solution: all that said, there may be a simple solution for you. You haven't provided any information on the type of data you want to pass in your array. If it is simple enough, you may try passing it on the command line as delimited text, and then break it up to use in your Rscript.
Here is an Rscript that shows you what I mean:
args = commandArgs(trailingOnly=TRUE)
filename = args[1]
cluster <- c(strsplit(args[2],"~"))
sprintf("Filename: %s",filename)
sprintf("Cluster list: %s",cluster)
print("Cluster:")
cluster
sprintf("First Item: %s",cluster[[1]][1])
Save it as "test.r" and try executing it with "Rscript test.r test.txt one~two" and you'll get the following output (tested on Rscript 46084, OpenBSD):
[1] "Filename: test.txt"
[1] "Cluster list: c(\"one\", \"two\")"
[1] "Cluster:"
[[1]]
[1] "one" "two"
[1] "First Item: one"
So, all you'd have to do on the perl side of things is join() your array using "~" or any other delimiter- it is highly dependent on your data, and you haven't provided it.
Summary: re-think how you want to communicate between perl and Rscript. Consider sending the data as a delimited string (if it's the right size) and breaking it up on the other side. Look into IPC if that won't work, consider environment variables or other options. There is no way to send an array reference on the command-line.
Note: you may want to read up on security risks of different system calls in perl.

Can't fill bash array

I'm running Ubuntu 14.04 and am trying to fill an array in a shell script so that I can loop over it and utilize its contents to fill a text file. However, there's a snag: it doesn't seem to be filling.
I've simplified the larger script that I'm working with down to the essential issue, reprinted below:
WL_START=1
WL_END=5
WL_INC=1
wl_range=$(seq $WL_START $WL_INC $WL_END)
declare -a WL
for i in $wl_range # loop through sequence and fill array
do
WL[$i]=${wl_range[$i]}
done
echo $wl_range
echo ${wl_range[1]}
echo $WL
echo ${WL[1]}
However, my output looks like this:
1 2 3 4 5
empty line
empty line
empty line
Any ideas? I know that people say to just use seq to fill the array, but I had the same problem there as well.
Too much work.
WL=($(seq $WL_START $WL_INC $WL_END))
wl_range is a string consisting of space-delimited numbers, not an array. Your for loop should simply look like
for i in $wl_range; do
WL[i]=$i
done
That said, don't use the for loop; use #IgnacioVazquez-Abrams' answer.

Shell script split a string by space

The bash shell script can split a given string by space into a 1D array.
str="a b c d e"
arr=($str)
# arr[0] is a, arr[1] is b, etc. arr is now an array, but what is the magic behind?
But, what exactly happened when we can arr=($str)? My understanding is the parenthesis here creates a subshell, but what happen after that?
In an assignment, the parentheses simply indicate that an array is being created; this is independent of the use of parentheses as a compound command.
This isn't the recommended way to split a string, though. Suppose you have the string
str="a * b"
arr=($str)
When $str is expanded, the value undergoes both word-splitting (which is what allows the array to have multiple elements) and pathname expansion. Your array will now have a as its first element, b as its last element, but one or more elements in between, depending on how many files in the current working directly * matches. A better solution is to use the read command.
read -ra arr <<< "$str"
Now the read command itself splits the value of $str without also applying pathname expansion to the result.
It seems you've confused
arr=($str) # An array is created with word-splitted str
with
(some command) # executing some command in a subshell
Note that
arr=($str) is different from arr=("$str")in that in the latter, the double quotes prevents word splitting ie the array will contain only one value -> a b c d e.
You can check the difference between the two by the below
echo "${#arr[#]}"

PowerShell collapses string array into single string when stored as second dimension

For some reason PowerShell takes an array of strings and converts it into a single string (or perhaps a character array?) when it is set as the second dimension of a two dimensional array:
Here is the initial output of the $path array:
PS C:\Users\crd> $path
C:
Program Files (x86)
Common Files
Adobe
ARM
1.0
armsvc.exe
The path[0] array entry is a string value:
PS C:\Users\crd> $path[0]
C:
Now we set the first value in the $test[] array equal to our string array:
PS C:\Users\crd> $test[0]=$path
You can see that the entire string array has been merged:
PS C:\Users\crd> $test[0]
C: Program Files (x86) Common Files Adobe ARM 1.0 armsvc.exe
Why is this? I'm sure Microsoft documented this somewhere but I'm having a hard time finding it.
I would expect the output to remain unchanged. Note the following output:
PS C:\Users\chris> $test[0][0]
C
I would like this to be the same as the $path[0] output which was C:. Why is this merge occurring?
you changed your hash of items into a single string value. works as expected.

Resources