0

I have a script tempenv which I'd like to use as follows:

$ tempenv ls -l

tempenv looks like this:

#!/bin/bash
setarch ... /bin/bash -c $@

However, it doesn't work as I intend. Instead, it only runs the first arg, ignoring anything else. That is tempenv ls -l runs as if tempenv ls.

3 Answers3

3

The shell's -c option expects the command line as one argument, and $@ splits ls -l into two. (So would "$@", just that it would keep argument strings with whitespace intact, so it doesn't directly help either.)

So, assuming you want to pass an actual command line, you'll have to either pass just a single string to the script, and pass it on with sh -c "$1", or if you like, join all arguments to the script into one string, and then use sh -c "$*", i.e.

#!/bin/bash
setarch ... /bin/bash -c "$*"

See:

This would support including all shell syntax in the command line, e.g.

tempenv 'ls -l; echo $SOMEVAR'
tempenv '[ some test ] && echo true'

But on the other hand, arguments that are supposed to contain whitespace, e.g. file names with such, need to be quoted twice, e.g.

tempenv 'ls -l "Some Document.txt"'
ilkkachu
  • 138,973
3

man bash:

-c
If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, the first argument is assigned to $0 and any remaining arguments are assigned to the positional parameters. The assignment to $0 sets the name of the shell, which is used in warning and error messages.

tempenv () { bash -c 'set -x; : "$@"' foo "$@"; }

tempenv ls -l 'foo bar'

  • : ls -l 'foo bar'

So this would work for you:

#!/bin/bash
setarch ... /bin/bash -c '"$@"' tempenv-subshell "$@"
Hauke Laging
  • 90,279
1

Given that you're invoking your tempenv script as tempenv ls -l, that is passing it two arguments: a command name and an argument for that command, it sounds like you actually want:

#!/bin/sh -
exec setarch ... "$@"

That is, you want your tempenv to run the given command with the given arguments under that different architecture.

If you had really wanted it to have some shell interpret some code under that different architecture, you'd have called it as tempenv 'ls -l' for that ls -l code to be interpreted by the shell of your choice here. For which the code would look like:

#! /bin/sh -
if [ "$#" -ne 1 ]; then
  printf >&2 '%s\n' "Usage: $0 <code-in-bash-language>"
  exit 1
fi
bash_code=$1
exec setarch ... /bin/bash -c -- "$bash_code"