19

I am trying to get a bash script that generates JSDoc for given parameters like this

./jsdoc.sh file.js another.js maybe-a-third.js

I am getting stuck on how to pass an unknown quantity of parameters to the next shell command.

(also, don't know how to check if param exists, only if not exitst if [ -z ... ])

This code works for up to two parameters, but obviously not the right way to go about it...

#!/bin/bash

# would like to know how to do positive check
if [ -z "$1" ]
then echo no param
else
        d=$PWD
        cd ~/projects/jsdoc-toolkit/

        # this bit is obviously not the right approach
        if [ -z "$2" ]
        then java -jar jsrun.jar app/run.js -a -t=templates/jsdoc/ $d/$1
        else java -jar jsrun.jar app/run.js -a -t=templates/jsdoc/ $d/$1 $d/$2
        fi

        cp -R out/jsdoc $d
fi

Any other pointers of how I could achieve this would be appreciated.

Edit: Updated script according to @skjaidev's answer - happy days ;)

#!/bin/bash

d=$PWD

for i in $*; do
    params=" $params $d/$i"
done

if [ -n "$1" ]; then
        cd ~/projects/jsdoc-toolkit/
        java -jar jsrun.jar app/run.js -a -t=templates/jsdoc/ $params
        cp -R out/jsdoc $d
fi
Billy Moon
  • 57,113
  • 24
  • 136
  • 237

4 Answers4

18

$* has all the parameters. You could iterate over them

for i in $*;
do
    params=" $params $d/$i"
done
your_cmd $params
jman
  • 11,334
  • 5
  • 39
  • 61
  • 15
    In this case, always use `"$@"` instead of `$*` -- the former will preserve arguments that contain whitespace, the latter will be subject to shell word splitting. – glenn jackman Aug 05 '11 at 22:05
  • 3
    Even though `"$@"` will preserve spaces in its expansion, the subsequent expansion of `$i` will undo the effect and when `$params` is expanded in the last line then filenames with embedded whitespace will still result in multiple arguments where one was expected. A Bash-specific solution is to use arrays as proposed by @glennjackman – Greg A. Woods Aug 01 '17 at 23:17
  • this will **not** work with parameters that contain whitespaces – phil294 Oct 14 '17 at 20:15
17

To handle arguments that contain whitespace, use "$@" to iterate, and store the for later use in an array.

#!/bin/bash
if (( $# == 0 )); then
  echo "usage: $0 file ..."
  exit
fi
dir=$(pwd)
declare -a params
for file in "$@"; do params+=( "$dir/$file" ); done
cd ~/projects/jsdoc-toolkit/
java -jar jsrun.jar app/run.js -a -t=templates/jsdoc/ "${params[@]}"
cp -R out/jsdoc "$dir"
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
4

-n is the inverse of -z, and "$@" is the canonical way to pass all parameters on to a subcommand. This and more can be found via man bash.

pyroscope
  • 4,120
  • 1
  • 18
  • 13
  • That's great - almost solved. Last thing is how do I prepend `$d/` to each paramater, to mimic `$d/$1 $d/$2` but with `$@`? – Billy Moon Aug 05 '11 at 21:54
1

Bash-specific features (arrays in this case) can be avoided through careful use of the IFS variable and the special $@ parameter.

#!/bin/sh

dir=$(pwd)

NEW_ARGV=""
# carefully modify original arguments individually and separate them with newlines
# in a new variable (in case they contain spaces)
NEW_ARGV=""
for var in "${@}"
do
    NEW_ARGV="${NEW_ARGV}
${dir}/${var}"
done

SV_IFS=${IFS}
# temporarily set IFS to a newline as per NEW_ARGV setup
IFS="
"
# reset $@ with the modified newline-separated arguments
set -- ${NEW_ARGV}
IFS=${SV_IFS}

# for testing, demonstrate each param is preserved
c=0
for i in "${@}"
do
    c=`expr ${c} + 1`
    echo "args-via-var #${c}: \"${i}\""
done

cd ~/projects/jsdoc-toolkit/
java -jar jsrun.jar app/run.js -a -t=templates/jsdoc/ "${@}"
cp -R out/jsdoc "${dir}"

It's not necessary to reset $@, but doing so avoids messing with IFS in multiple places. Without going through $@ one must set IFS everywhere one expands $NEW_ARGV.

Those with an eye for detail will note that this method does not preserve parameters when they contain newlines. It would be possible to use any control character in place of newline, except of course NUL, and perhaps ASCII FS (file separator, aka ctrl-\) would be both meaningful and very unlikely to occur in a valid filename.

Greg A. Woods
  • 2,663
  • 29
  • 26