1

I'm receiving a list of operating systems, one per line, such as:

alpine/3.13
alpine/edge
alt/Sisyphus
alt/p9
apertis/v2019.5

I need to massage each line into two parameters to yield:

lxc launch images:alpine/3.13 alpine-3-13
lxc launch images:alpine/edge alpine-edge
lxc launch images:alt/Sisyphus alt-Sisyphus
lxc launch images:alt/p9 alt-p9
lxc launch images:apertis/v2019.5 apertis-v2019-5

and then run those commands. Note the second parameter has had everything non-alphanumeric switched to hyphens. I came up with the following:

echo alpine/3.13 | sed 'h;s#[/.]#-#g;x;G;s/\n/ /' | xargs -ti lxc launch images:{}

Unfortunately, although the command that xargs runs looks correct, instead of passing two arguments to lxc, xargs passes the entire thing as a single argument, so lxc tries to download an image named "alpine/3.13 alpine-3-13", instead of downloading the image named alpine/3.13 and using it to create a container named alpine-3-13.

Is there a way to pass lxc two separate arguments?

Example output:

# echo alpine/3.13 | sed 'h;s#[/.]#-#g;x;G;s/\n/ /' | xargs -ti lxc launch images:{}
lxc launch images:alpine/3.13 alpine-3-13
Creating the instance
Error: Failed instance creation: The requested image couldn't be found
# lxc launch images:alpine/3.13 alpine-3-13
Creating alpine-3-13
Starting alpine-3-13
<works correctly>

Complete (working) final command based on below input from KamilCuk and markp-fuso:

lxc image list images: | grep -v cloud | grep -Po '^\| \K[^ ]+(?=.+x86_64.+CONTAINER)' | sed 'h;s#[^[:alnum:]]#-#g;x;G;s/\n/ /;s/^ */images:/' | xargs -n2 lxc launch
Pascal
  • 267
  • 2
  • 10
  • `that runs looks correct` how can that `sed` "look" correct? – KamilCuk Apr 27 '21 at 20:11
  • The t param to xargs tells it to output what it is about to run. It says it is going to run "lxc launch images:alpine/3.13 alpine-3-13", which works fine when pasted to a bash prompt. – Pascal Apr 27 '21 at 20:14

2 Answers2

0

Looks over-complicated - you do not need to use hold space at all. For remembering stuff from pattern and shuffling it use backreferences. Just:

echo alpine/3.13 | sed 's#\(.*\)/\(.*\)#lxc launch images:& \1-\2#'

You could run like:

echo alpine/3.13 | sed 's#\(.*\)/\(.*\)#images:& \1-\2#' | xargs -n2 lxc launch

or just:

eval "$(echo alpine/3.13 | sed 's#\(.*\)/\(.*\)#lxc launch images:& \1-\2#')"

But I would go with proper code anyway.

func() {
  arg=${1//\//-}
  lxc launch images:"$1" "$arg"
}
while IFS= read -r line; do
     func "$line"
done <<EOF
alpine/3.13 
EOF

or with same function:

export -f func
echo alpine/3.13 | xargs -d '\n' -n1 bash -c 'func "$@"' _

Is there a way to pass lxc two separate arguments?

Yes, but xargs has to know what to do with it. You can't "glue" two arguments with something in xargs - -i grabs only one argument. You could glue the images: in sed and then pass it, using your sed hold space shuffling, it's:

echo alpine/3.13 | sed 'h;s#[/.]#-#g;x;G;s/\n/ /;s/^ */images:/' | xargs -t -n2 lxc launch

but I see no value in xargs here at all anyway.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Your first example displays a command but doesn't actually run it. Most of your examples do not replace all the non-alphanumeric characters.in the second parameter (currently that is only slashes and periods). Your last example does appear to work! Thank you! – Pascal Apr 27 '21 at 20:42
0

OP's examples start with echo <operating_system_string> which I'm going to assume implies the input file (full of <operating_systen_string>'s) is being passed through some sort of loop, and upon each pass through the loop a variable is being assigned the current <operating_system_string>.

Key point here is that a variable is going to be used to hold the current <operating_system_string>.

I'm wondering if OP can use parameter substitution to accomplish the desired task, eg:

$ osname='alpine/3.13'
$ echo "${osname//[^[:alnum:]]/-}"     # replace all non-alphanumerics with a '-'
alpine-3-13

So making the lxc call would look like:

$ echo lxc launch images:"${osname}" "${osname//[^[:alnum:]]/-}"
lxc launch images:alpine/3.13 alpine-3-13

$ lxc launch images:"${osname}" "${osname//[^[:alnum:]]/-}"

Taking a run at the list of OS names ...

Input file:

$ cat oslist
alpine/3.13
alpine/edge
alt/Sisyphus
alt/p9
apertis/v2019.5

Running the file through a while loop:

while read -r osname
do
    echo lxc launch images:"${osname}" "${osname//[^[:alnum:]]/-}"
done < oslist

Which generates:

lxc launch images:alpine/3.13 alpine-3-13
lxc launch images:alpine/edge alpine-edge
lxc launch images:alt/Sisyphus alt-Sisyphus
lxc launch images:alt/p9 alt-p9
lxc launch images:apertis/v2019.5 apertis-v2019-5

Once OP is satisfied with the results the echo could be removed to instead invoke the lxc call on each pass through the loop.

markp-fuso
  • 28,790
  • 4
  • 16
  • 36