views:

482

answers:

3

I need a simple busybox sh wrapper which will do:

IF "-Q" PARAMETER IS PROVIDED THEN  
    acommand ALL PARAMETERS BUT "-Q" 2>&1 1>/dev/null  
ELSE  
    acommand ALL PARAMETERS  
FI

Parameters may include spaces.

BTW I want to run the script with busybox sh and it doesn't support arrays.

A: 

It's a pity that you need to handle spaces in the arguments otherwise this might work:

#!/bin/sh
Q=0
ARGS=

while [ $# -ge 1 ]; do
    case $1 in
        -Q)
            Q=1
            ;;
        *)
            ARGS="$ARGS $1"
            ;;
    esac
    shift
done

if [ $Q -eq 1 ] ; then
    acommand $ARGS 2>&1 1>/dev/null
else
    acommand $ARGS
fi

EDIT:

So this version handles spaces, at the expense of interpreting back-ticks.

#!/bin/busybox ash
Q=0
ARGS=

while [ $# -ge 1 ]; do
    case $1 in
        -Q)
            Q=1
            ;;
        *)
            ARGS="$ARGS \"$1\""
            ;;
    esac
    shift
done

if [ "$Q" -eq 1 ] ; then
    eval acommand $ARGS 2>&1 1>/dev/null
else
    eval acommand $ARGS
fi

I think to have a complete solution you are going to have to code it in C, which will be a bit ugly.

Douglas Leeder
The only way I could see supporting spaces is with arrays - but I don't know if busybox sh supports arrays?
Douglas Leeder
Unfortunately, it doesn't.
Erdem Güven
A: 

This uses bash arrays - but I see from the comments to another answer that the code isn't supposed to run under bash (despite the bash tag originally applied to the question); it is meant to run under the busybox shell.

I'm almost certain it doesn't answer the question because the question is substantially unanswerable given the limitations of busybox. In times past, I have used a custom program I called 'escape' to build up an argument string that can be eval'd to get the original arguments - spaces and all. But that requires support from outside the shell.


This solution only uses 'bash'. I'm not sure it is fully idiomatic bash code, but it works.

#!/bin/bash

i=0
Qflag=0
for arg in "$@"
do
    if [ "X$arg" = "X-Q" ]
    then Qflag=1
    else args[$((i++))]=$arg
    fi
done

if [ $Qflag = 1 ]
then exec acommand "${args[@]}" 2>&1 >/dev/null
else exec acommand "${args[@]}"
fi

The first loops builds up an array, args, with the arguments to the script, except it doesn't add '-Q' to the list and records its presence in variable Qflag.

The if statement at the end notes whether Qflag was set to 1, and if so, sends the errors from 'acommand' to standard output and sends regular standard output to /dev/null (which is different from the effect if the I/O redirections are reversed - that would send standard output to /dev/null and send standard error to the same place, forcing silence on 'acommand').

The use of 'exec' is a trivial optimization that simplifies exit status handling in this case.

Tested with 'acommand' that prints its arguments on separate lines:

#!/bin/sh
for arg in "$@"
do echo "$arg"
done

and with command lines such as:

bash wrapper.sh -c -d 'arg with spaces'

which produces the output:

-c
-d
arg with spaces

Obviously, with the I/O redirection in place, there is no output from:

bash wrapper.sh -c -Q -d 'arg with spaces'

However, if you omit the I/O redirection, you get to see the same output.

Jonathan Leffler
Since you're using Bash, it's not necessary to use both quotes and an "X" in your test - quotes alone will do.
Dennis Williamson
@Dennis Williamson: Fine - I grew up in the old school; sometime in the next 25 years, I'll adapt to that. What I wrote _does_ work, and the cost difference is minimal (as in, unmeasurable). Also, in fact, all POSIX shell test operators should be OK without the X's; however, I have used enough not quite POSIX-compliant shells not to risk getting burned.
Jonathan Leffler
I grew up in the "old school", too. Lots of my older script have X's in them.
Dennis Williamson
+1  A: 

It's possible to do it all in busybox's ash shell:

#!/bin/sh
for i in "${@}"
do
    if [ "$i" = "-Q" ]
    then
        flagQ=1
    else
        args="$args \"$i\""
    fi
done
if [ "$flagQ" = "1" ]
then
    eval acommand "$args" 2>&1 1>/dev/null
else
    eval acommand "$args"
fi
Dennis Williamson
The eval won't work when I use "He said don't!" as an argument; it is also unhappy if I write "He said use \`ls\` and I did". In the first case, you have unbalanced single quotes messing up the interpetation; in the second, you'll execute the 'ls' command.
Jonathan Leffler
`diff <(./myscript "he said use \`ls\` and I did") <(./acommand "he said use \`ls\` and I did")` yields no difference. This will also execute `ls` : `echo "He said use \`ls\` and I did"`, but you're right about the apostrophe.
Dennis Williamson
...that's using your `acommand` script in the `diff` command.
Dennis Williamson
I've edited my script to fix the apostrophe problem.
Dennis Williamson