How to access command line arguments of the caller inside a function?
Asked Answered
I

10

125

I'm attempting to write a function in bash that will access the scripts command line arguments, but they are replaced with the positional arguments to the function. Is there any way for the function to access the command line arguments if they aren't passed in explicitly?

# Demo function
function stuff {
  echo $0 $*
}

# Echo's the name of the script, but no command line arguments
stuff

# Echo's everything I want, but trying to avoid
stuff $*
Infix answered 29/4, 2010 at 21:31 Comment(3)
I am kind of confused , you want the args with out passing them?Safekeeping
Yes, the point is to get too the command line arguments from inside a function without passing them in as functional arguments. It has to do with an error handling situation in which I want to do error handling based on command line arguments independently of the arguments passed into the function.Infix
FYI, $* is extremely buggy -- it'll change ./yourScript "first argument" "second argument" to ./yourscript "first" "argument" "second" "argument", or change ./yourscript '*.txt' to something like ./yourscript one.txt two.txt despite the quotes.Application
S
56

My reading of the Bash Reference Manual says this stuff is captured in BASH_ARGV, although it talks about "the stack" a lot.

#!/bin/bash

shopt -s extdebug

function argv {
  for a in ${BASH_ARGV[*]} ; do
    echo -n "$a "
  done
  echo
}

function f {
  echo f $1 $2 $3
  echo -n f ; argv
}

function g {
  echo g $1 $2 $3
  echo -n g; argv
  f
}

f boo bar baz
g goo gar gaz

Save in f.sh

$ ./f.sh arg0 arg1 arg2
f boo bar baz
fbaz bar boo arg2 arg1 arg0
g goo gar gaz
ggaz gar goo arg2 arg1 arg0
f
fgaz gar goo arg2 arg1 arg0
Subversion answered 29/4, 2010 at 22:8 Comment(3)
Do note that itterating the array like that causes the args to be in reverse order from the command line.Arc
${BASH_ARGV[*]} should arguably be "${BASH_ARGV[@]}" with double quotes and @Concourse
BASH_ARGV is not only in reverse order. In addition if it is accessed in a source'd script it contains the path of the sourced script as argument, too. Because of that I finally deviced to copy the script arguments to a new array like export SCRIPT_ARG=("${@}") and use this in a function.Repeater
Z
119

If you want to have your arguments C style (array of arguments + number of arguments) you can use $@ and $#.

$# gives you the number of arguments.
$@ gives you all arguments. You can turn this into an array by args=("$@").

So for example:

args=("$@")
echo $# arguments passed
echo ${args[0]} ${args[1]} ${args[2]}

Note that here ${args[0]} actually is the 1st argument and not the name of your script.

Zygophyllaceous answered 29/4, 2010 at 21:40 Comment(5)
This doesn't address the question - it's asking about passing the command-line arguments along to a shell function.Carmelinacarmelita
@Jefromi, actually, it answers the question perfectly. You can use the args array from inside a function, if you initialize it beforehand as described.Ea
I find this much cleaner than iterating over the args.Reeducate
This is simple and easy. Great answer. You posted this over 7 years ago, so hello from the future: July 2017Timely
Even better would be quoting like echo "${args[0]} ${args[1]} ${args[2]}", or the arguments are subject to filename expansion.Espinoza
S
56

My reading of the Bash Reference Manual says this stuff is captured in BASH_ARGV, although it talks about "the stack" a lot.

#!/bin/bash

shopt -s extdebug

function argv {
  for a in ${BASH_ARGV[*]} ; do
    echo -n "$a "
  done
  echo
}

function f {
  echo f $1 $2 $3
  echo -n f ; argv
}

function g {
  echo g $1 $2 $3
  echo -n g; argv
  f
}

f boo bar baz
g goo gar gaz

Save in f.sh

$ ./f.sh arg0 arg1 arg2
f boo bar baz
fbaz bar boo arg2 arg1 arg0
g goo gar gaz
ggaz gar goo arg2 arg1 arg0
f
fgaz gar goo arg2 arg1 arg0
Subversion answered 29/4, 2010 at 22:8 Comment(3)
Do note that itterating the array like that causes the args to be in reverse order from the command line.Arc
${BASH_ARGV[*]} should arguably be "${BASH_ARGV[@]}" with double quotes and @Concourse
BASH_ARGV is not only in reverse order. In addition if it is accessed in a source'd script it contains the path of the sourced script as argument, too. Because of that I finally deviced to copy the script arguments to a new array like export SCRIPT_ARG=("${@}") and use this in a function.Repeater
S
24
#!/usr/bin/env bash

echo name of script is $0
echo first argument is $1
echo second argument is $2
echo seventeenth argument is $17
echo number of arguments is $#

Edit: please see my comment on question

Safekeeping answered 29/4, 2010 at 21:33 Comment(0)
C
22

Ravi's comment is essentially the answer. Functions take their own arguments. If you want them to be the same as the command-line arguments, you must pass them in. Otherwise, you're clearly calling a function without arguments.

That said, you could if you like store the command-line arguments in a global array to use within other functions:

my_function() {
    echo "stored arguments:"
    for arg in "${commandline_args[@]}"; do
        echo "    $arg"
    done
}

commandline_args=("$@")

my_function

You have to access the command-line arguments through the commandline_args variable, not $@, $1, $2, etc., but they're available. I'm unaware of any way to assign directly to the argument array, but if someone knows one, please enlighten me!

Also, note the way I've used and quoted $@ - this is how you ensure special characters (whitespace) don't get mucked up.

Carmelinacarmelita answered 29/4, 2010 at 22:4 Comment(0)
V
7
# Save the script arguments
SCRIPT_NAME=$0
ARG_1=$1
ARGS_ALL=$*

function stuff {
  # use script args via the variables you saved
  # or the function args via $
  echo $0 $*
} 


# Call the function with arguments
stuff 1 2 3 4
Vaccination answered 29/4, 2010 at 21:40 Comment(0)
C
4

One can do it like this as well

#!/bin/bash
# script_name function_test.sh
function argument(){
for i in $@;do
    echo $i
done;
}
argument $@

Now call your script like

./function_test.sh argument1 argument2
Clamor answered 14/7, 2016 at 5:6 Comment(1)
function print() { is an amalgam between two different function declaration forms -- function print {, which is legacy ksh syntax that bash supports for backwards compatibility with pre-POSIX (which is to say, pre-1991) ksh, and print() {, which is POSIX-standardized. Consider using one or the other for wider compatibility with other shells; see also wiki.bash-hackers.org/scripting/obsoleteApplication
I
2

This is @mcarifio response with several comments incorporated:

#!/bin/bash

shopt -s extdebug

function stuff() {
  local argIndex="${#BASH_ARGV[@]}"
  while [[ argIndex -gt 0 ]] ; do
    argIndex=$((argIndex - 1))
    echo -n "${BASH_ARGV[$argIndex]} "
  done
  echo
}

stuff

I want to highlight:

Insistent answered 29/10, 2021 at 12:34 Comment(0)
A
1

You can use the shift keyword (operator?) to iterate through them. Example:

#!/bin/bash
function print()
{
    while [ $# -gt 0 ]
    do
        echo "$1"
        shift 1
    done
}
print "$@"
Antionetteantioxidant answered 19/11, 2014 at 21:26 Comment(1)
function print() { is an amalgam between two different function declaration forms -- function print {, which is legacy ksh syntax that bash supports for backwards compatibility with pre-POSIX (which is to say, pre-1991) ksh, and print() {, which is POSIX-standardized. Consider using one or the other for wider compatibility with other shells; see also wiki.bash-hackers.org/scripting/obsoleteApplication
E
1

I do it like this:

#! /bin/bash

ORIGARGS="$@"

function init(){   
  ORIGOPT= "- $ORIGARGS -" # tacs are for sed -E 
  echo "$ORIGOPT"
}
Earthlight answered 15/1, 2020 at 17:23 Comment(0)
A
0

The simplest and likely the best way to get arguments passed from the command line to a particular function is to include the arguments directly in the function call.

# first you define your function 
function func_ImportantPrints() {
    printf '%s\n' "$1" 
    printf '%s\n' "$2" 
    printf '%s\n' "$3" 
} 
# then when you make your function call you do this:  
func_ImportantPrints "$@" 

This is useful no matter if you are sending the arguments to main or some function like func_parseArguments (a function containing a case statement as seen in previous examples) or any function in the script.

Adiabatic answered 23/5, 2021 at 21:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.