Given:
array(a1)=123
array(b1)=456
My command is:
for test in ${array[#]}; do
echo "Hello "$!test "$test" Hi"
done
The output is:
Hello test 123 Hi
Hello test 456 Hi
Expected output is:
Hello a1 123 Hi
Hello b1 456 Hi
test is a normal variable and doesn't store any reference to the array. In your case writing $!test is the same as writing ${someUndefinedVariable}test (see ✱). The undefined variable will expand to the empty string. test is a literal string.
To print the keys and values, you have to iterate over the keys and retrieve the corresponding values manually:
declare -A array
array[a1]=123
array[b1]=456
for key in "${!array[#]}"; do
echo "key=$key, value=${array[$key]}"
done
By the way, I'm suprised your command even ran without an error; a closing " is missing. You cannot nest quotation marks. After the first " the second " will end quotation:
|quoted| |quoted |started quote without end -->
| | | | |
"Hello "$!test "$test" Hi"
| | | |
|unquoted |unquoted
✱ $! is actually a special variable that contains the process number of the last background command. Since you did not start any background commands in your session $! is empty.
Related
I have the following challenge:
my source_file.txt contains:
track001="alpha"
some text ... but also again the string track001 without " symbol... some more text
track002="beta"
some text ... but also again the string track002 without " symbol ... some more text
track027="gamma"
some text ... but also again the string track003 without " symbol ... some more text
track...="..."
... about 30 entries.
Now, I want to
search for the string next to trackxxx=" (=> find the alpha, beta and gamma string)
afterwards provide the list to the user for further pre-processing in the terminal:
| Reference | Title | Status |
|---------- |--------| ------------------|
| 001 | alpha | [ not selected ] |
| 002 | beta | [ not selected ] |
| ... | ... | [ not selected ] |
| 027 | gamma | [ not selected ] |
type Reference number (xxx): < user prompt>
change Status (selected = 1 / not selected = 0): < user prompt >
I thought about:
to copy the file and delete all lines which do not start with trackxxx=" but I guess there is nice sed which does the magic.
I need to paste all into a matrix to ease the pre-processing
for the pre-processing I would like to keep it simple (terminal interaction) no zenity etc.. Maybe someone has an idea to make the selector operation more user friendly.
Appreciate your support, thank you!
As a partial answer, because of the request for explanation of my comments:
sed -n 's/^track\(.*\)="\([^"]*\).*/ \1 \2 /p' will give you a list of
001 alpha
002 beta
...
027 gamma
which can be fed into a for-loop in bash to do the actual processing.
sed -n will not produce output, unless a line is explicitly printed
s/pattern/replacement/ replaces the pattern by the replacement
^track matches track if it is at the beginning of a line (^)
\(.*\) creates a capture group; the \( opens the capture group and the \) closes it. The capture group contains all characters up to the next element in the pattern
-=" This is the next element in the pattern: literal ="
\([^"]*\) second capture group. All character that are not " are added to this group.
.* the rest of the line. Will most probably begin with a ", but if you forget the closing ", that's ok too.
-The replacement string \1 \2 is a combination of the two capture group, \1 for the first and \2 for the second.
p Explicitly print this line if the pattern is matched. Because of the -n, normal output is suppressed, and you will get only the explicitly printed lines.
I'm trying to print text to an output file, and I need my output file to match the proper formatting exactly.
I need to do this so that when my program's output is compared to what the proper output should be, (talking large output files here) a simple string comparison of the output files should flag them as perfectly identical.
Here is an example of the EXACT expected output:
| Item 1234 | CALCULATOR | $ 0.45 |
| Item 5678 | USA_FLAG | $ 10.99 |
| Item 9012 | WITCH_BROOM | $ 18.00 |
Notice how with this formatting there are variable amounts of spaces after each string and before the double numbers, but they still manage to line up perfectly.
So how do you output this kind of formatting?
I'm assuming there is something about fprintf() that I just don't know, but again, I don't know soooooooooooooo
You can specify flags and width in the printf format string e.g.
printf( "%10s", "test" ) will print a 10 characters and pad with spaces if the argument is shorter. e.g (dots added for spaces)
test......
You can also specify justification e.g.
printf( "%-10s", "test" )
......test
I have wrote a script that throws the output of running node processes with the cwd of that process and I store the value in an array using for loop and do echo that array.
How can I able to get the user enter the index of array regarding the output that the script throws and show the output against that input generated by user
Example Myscript
array=$(netstat -nlp | grep node)
for i in ${array[*]}
do
echo $i
done
output is something like that
1056
2064
3024
I want something more advance. I want to take input from user like
Enter the regarding index from above list = 1
And lets suppose user enter 1
Then next output should be
Your selected value is 2064
Is it possible in bash
First, you're not actually using an array, you are storing a plain string in the variable "array". The string contains words separated by whitespace, so when you supply the variable in the for statement, the unquoted value is subject to Word Splitting
You need to use the array syntax for setting the array:
array=( $(netstat -nlp | grep node) )
However, the unquoted command substitution still exposes you to Filename Expansion. The best way to store the lines of a command into an array is to use the mapfile command with a process substitution:
mapfile -t array < <(netstat -nlp | grep node)
And in the for loop, make sure you quote all the variables and use index #
for i in "${array[#]}"; do
echo "$i"
done
Notes:
arrays created with mapfile will start at index 0, so be careful of off-by-one errors
I don't know how variables are implemented in bash, but there is this oddity:
if you refer to the array without an index, you'll get the first element:
array=( "hello" "world" )
echo "$array" # ==> hello
If you refer to a plain variable with array syntax and index zero, you'll get the value:
var=1234
echo "${var[0]}" # ==> 1234
a=0
b=1
for a in ${my_array[#]}
do
for b in ${my_array[#]}
do
if [ " ${my_array[a]} " = " ${my_array[b]} " ]
then
continue
((a++))
fi
done
((b++))
done
Hi. I want to compare 2 strings. They are in the same array. If they are same, I just print it one of them. How can I do that ? I write some code. There are 2 thins (a and b ) a's first value is 0 and it stores first element of array. b's first value is 1 and it stores 1.element of array. I want to compare them and if they are same strings, I just print one of them .so I use "continue". think my code is true, but it doesn't work .there is a mistake which I can't see. Can you help me ?
for example it runs like that .
Enter words :
erica 17
sally 16
john 18
henry 17
john 18
jessica 19
as you see there are 2 john 18. I don't want both of them. My program will be check there are 2 strings are the same . If they are same I will just use one of them .
The if statment "=" - assign, "==" - compare.
If I understand correctly, you want to uniquify the elements of an array. If this is right, then the following stackoverflow question (How can I get unique values from an array in Bash?) appears to answer it in the following one-liner:
echo "${my_array[#]}" | tr ' ' '\n' | sort | uniq
Unfortunately, since your input words (or elements of array) contain spaces, the above will not work as expected. The issue is because the first echo will flatten-out the array into space-separated elements. The solution to this would be to use printf and remove 'tr'. Here it is...
printf '%s\n' "${my_array[#]}" | sort | uniq -c
But this alters the position of elements wrt the original array. Hope that is fine?
You can use sort and uniq to be able to get your desired output:
echo "${my_array[#]}" | tr ' ' '\n' | sort | uniq -c | tr '\n' ' '
And if you have spaces in your input you can use this:
printf '%s\n' "${my_array[#]}" | sort | uniq -c
That way you will get the number of times the string occurred but it will be printed just once.
My bash script needs to read values from a properties file and assign them to a number of arrays. The number of arrays is controlled via configuration as well. My current code is as follows:
limit=$(sed '/^\#/d' $propertiesFile | grep 'limit' | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
for (( i = 1 ; i <= $limit ; i++ ))
do
#properties that define values to be assigned to the arrays are labeled myprop## (e.g. myprop01, myprop02):
lookupProperty=myprop$(printf "%.2d" "$i")
#the following line reads the value of the lookupProperty, which is a set of space-delimited strings, and assigns it to the myArray# (myArray1, myArray2, etc):
myArray$i=($(sed '/^\#/d' $propertiesFile | grep $lookupProperty | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'))
done
When I attempt to execute the above code, the following error message is displayed:
syntax error near unexpected token `$(sed '/^\#/d' $propertiesFile | grep $lookupProperty | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')'
I am quite sure the issue is in the way I am declaring the "myArray$i" arrays. However, any different approach I tried produced either the same errors or incomplete results.
Any ideas/suggestions?
You are right that bash does not recognize the construct myArray$i=(some array values) as an array variable assignment. One work-around is:
read -a myArray$i <<<"a b c"
The read -a varname command reads an array from stdin, which is provided by the "here" string <<<"a b c", and assigns it to varname where varname can be constructs like myArray$i. So, in your case, the command might look like:
read -a myArray$i <<<"$(sed '/^\#/d' $propertiesFile | grep$lookupProperty | tail -n 1 | cut -d "=" -f2- | seds/^[[:space:]]*//;s/[[:space:]]*$//')"
The above allows assignment. The next issue is how to read out variables like myArray$i. One solution is to name the variable indirectly like this:
var="myArray$i[2]" ; echo ${!var}