0

I have the following script which retrieves info from mysql

#!/bin/bash
set -f       
IFS=$'\n'

arr=($(sudo mysql -u root -h localhost -e "USE mydb;SELECT * FROM users"))

for i in "${arr[@]}" do echo "$i}" done

When I run the previous script I get:

id      firstname       lastname        phonenumber     password        email   ip}
5       User    User    111111111111    Passtest1       testuser@gmail.com      147.236.147.91}

Here is the problem: I want to print one single key value as I run:

#!/bin/bash

set -f
IFS=$'\n'

arr=($(sudo mysql -u root -h localhost -e "USE mydb;SELECT * FROM users"))

echo ${arr[ip]}

Then I get:

id      firstname       lastname        phonenumber     password        email   ip

How can I print id value, which in this case is 5?

AdminBee
  • 22,803
Iosef
  • 3
  • What are you expecting it to print if there are multiple lines? If you're looking to have the whole table stored in a shell data structure and to slice one column off it, you can't get that directly with Bash, since it doesn't support even two-dimensional arrays. (Well, you can fake them, but slicing off that one column still needs to be done manually.) It's relatively easy to just read the lines in, and then split them when printing to just print that one column. – ilkkachu Aug 23 '21 at 08:54
  • 2
    Do yourself a favour and use a proper programming language with a mysql API (perl/pyhon/php...). Doing it in shell reliably is almost impossible, especially with bash which has limited data structures and operators compared to more advanced shells like ksh93 or zsh. – Stéphane Chazelas Aug 23 '21 at 09:02
  • 2
    You also shouldn't have to run the mysql client command as root. – Stéphane Chazelas Aug 23 '21 at 09:04

1 Answers1

2

First, may I recommend that you run all shell scripts through shellcheck - also available as standalone program on many Linux distributions - to detect syntax errors. The echo $i} e.g. looks like a typo which only "works" because $i is the same as ${i}, and the additional } "only" leads to a stray } appended to the intended output.

Second, there seems to be a misconception on the use of arrays and variables here. You want to print the last column labeled ip from the "actual data line" of your output. Your use of

echo ${arr[ip]}

however would not work because you have neither declared (as in declare -A arr) nor "filled" arr as an associative array, meaning that dereferencing the array like that will not work - the shell will expect a numerical array index here. If you supply a text string (like ip) instead, the behavior will depend on the shell, though it will likely interpret that as a variable name, find that the variable is undefined (i.e. evaluates to the empty string), and then print only the first entry of the array (the first line in your case).

Also, even if you declare the array as associative, the matching of "column titles" to "array indices" will not be automatic; you have to do it manually if you want a targeted acces as you describe it to work.

Third, text processing is in most cases better performed using a text-processing tool such as awk instead of doing it in the shell. Since you want to ignore the header line and print the last column of the second line, I would recommend

sudo mysql -u root -h localhost -e "USE mydb;SELECT * FROM users" | awk 'NR==2{print $7}'

which will process the output of your sudo call invoking the mysql command through an awk program that will only process the second line (condition NR==2) and print the 7th column if that line is encountered.

Fourth, the best option is still to select data using the database tools themselves. I am no SQL expert, but I think a query such as

mysql -u root -h localhost -e "USE mydb; SELECT ip FROM users WHERE id='5'"

should work (but please verify with an uncritical example before production use).

AdminBee
  • 22,803
  • ${arr[ip]} is defined allright, it takes ip as a variable, and uses its numerical value as the index. Using zero if the variable is empty or undefined, like here. (If it contains a valid variable name, recursively digs through the referenced variables until it finds something that isn't.) – ilkkachu Aug 23 '21 at 08:41