0

Based on the values in the second column, I need to run another command on these values.

[root@box ~]# for i in $(openstack server list --all -c ID -f value); do openstack server show $i -f value -c name -c project_id | xargs printf '%-60s %s\n'; done
cf1-0                                  ebf0f23f424c4417afd3e7bbf4e3900f
sf1-3                                  ebf0f23f424c4417afd3e7bbf4e3900f
sf1-2                                  ebf0f23f424c4417afd3e7bbf4e3900f
sf1-0                                  ebf0f23f424c4417afd3e7bbf4e3900f

Here's an example of what I'm trying to do.

[root@box ~]# for i in $(openstack server list --all -c ID -f value); do openstack server show $i -f value -c name -c project_id | xargs printf "%-60s eval(openstack project show %s -f value -c name)"; done
 cf1-0                                  eval(openstack project show ebf0f23f424c4417afd3e7bbf4e3900f -f value -c name)

The substitution from the second %s in printf works correctly, but I can't figure out how to execute the command.

The command needs to be executed in the same shell, and I cannot use environment variables.

Thanks.

** OUTPUT OF COMMANDS **

Here, -c var1 -c var2 can be placed in any order. -f just means print out the values, not the identifier.

[root@box~]# openstack server list --all -c Name -c ID -f value
2534ce5a-04da-4c7d-9ad5-b7bc466ae612 cf1-0

[root@box ~]# openstack server show 2534ce5a-04da-4c7d-9ad5-b7bc466ae612 -f value -c name -c project_id
cf1-0
ebf0f23f424c4417afd3e7bbf4e3900f

[root@box ~]# openstack project show ebf0f23f424c4417afd3e7bbf4e3900f -f value -c name
core

Desired output
===============
cf1-0 core
8
  • Re: for var in $(...anything...), see BashPitfalls #1, and BashFAQ #1 describing the approach used in Inian's answer as a preferable alternative. Commented Feb 19, 2020 at 16:46
  • btw, I'm curious about the "cannot use environment variables" -- why would environment variables be part of an answer to this otherwise? Why can't they be used? (Clearly, you have some environment variables set -- if you didn't have a PATH, you couldn't be using unqualified command names). Commented Feb 19, 2020 at 16:49
  • Thanks @CharlesDuffy. This server is a management node which is part of a cloud infrastructure running custom based Linux software. We have been asked not to treat it like an ordinary server. I believe that extends to setting variables within bash scripts, as those would be exposed to the shell(?). In the long-term we should obtain this information via REST API, but I am looking for a quick solution right now via bash. Commented Feb 19, 2020 at 16:58
  • No, variables in scripts are not exposed to the parent shell. A program can only change the environment of its child processes, not of its parents; that's true whether or not that program is implemented as a shell script. Commented Feb 19, 2020 at 17:01
  • I was thinking of storing the variables in a [x][y] awk array, to avoid storing them in the shell. Then iterating through the elements of the [y] awk array. Commented Feb 19, 2020 at 17:01

2 Answers 2

2

Don't make things further convoluted by adding further levels of xargs. Recommend using a while loop reading the output at each stage and processing them further. The below works in bash with <(..) process substitution

#!/usr/bin/env bash

while read -r id instname; do
    proj="$(openstack server show "$id" -f value -c project_id)"
    [ -z "$proj" ] && break
    name="$(openstack project show "$proj" -f value -c name)"
    printf '%s %s\n' "$instname" "$name"
done < <(openstack server list --all -c ID -c Name -f value)
Sign up to request clarification or add additional context in comments.

Comments

0

Not very familiar with the openstack command, but a simple way of doing this in one line would be using awk with system function.

The command should look similar to this:

openstack server list --all -c ID -f value | awk -F'\t' '{ printf $1; system("eval openstack project show " $2 " -f value -c name") }'

4 Comments

Maverick, I believe I was not clear in the original question. We need two levels of recursion here. I've updated the question with the raw outputs and expected output. Thanks
Why would you put an eval in there? Calling system() already sends your data through a shell parsing pass (which is part of why it's insanely dangerous to use if you don't have complete control of all data substituted into the string).
(by comparison, even unquoted parameter expansions in shell skip the most dangerous parsing phases, performing only string splitting and glob expansion; but when system() in awk starts a shell, it has no way to indicate to that shell where the boundaries are between code and data).
As a starting point, see mywiki.wooledge.org/BashFAQ/048, keeping in mind that everything it says applies to system() even before you put an eval in it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.