Jak uzyskać dostęp do argumentów wiersza poleceń obiektu wywołującego wewnątrz funkcji?

101

Próbuję napisać funkcję w bash, która będzie miała dostęp do argumentów wiersza poleceń skryptów, ale są one zastępowane argumentami pozycyjnymi funkcji. Czy istnieje sposób, aby funkcja uzyskała dostęp do argumentów wiersza poleceń, jeśli nie są one jawnie przekazywane?

# 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 $*
DonGar
źródło
3
Jestem trochę zdezorientowany, chcesz argumentów bez ich przekazywania?
Ravi Vyas
4
Tak, chodzi o to, aby argumenty wiersza poleceń były pobierane z wnętrza funkcji bez przekazywania ich jako argumentów funkcjonalnych. Ma to związek z sytuacją obsługi błędów, w której chcę obsługiwać błędy w oparciu o argumenty wiersza poleceń niezależnie od argumentów przekazanych do funkcji.
DonGar
FYI, $*jest bardzo błędny - zmieni ./yourScript "first argument" "second argument"się ./yourscript "first" "argument" "second" "argument"lub zmieni ./yourscript '*.txt'na coś podobnego ./yourscript one.txt two.txtpomimo cytatów.
Charles Duffy

Odpowiedzi:

48

Czytając podręcznik bash ref mówi, że ten materiał jest przechwytywany w BASH_ARGV, chociaż dużo mówi o „stosie”.

#!/bin/bash

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

Zapisz w f.sh

$ ./f.sh arg0 arg1 arg2
f boo bar baz
farg2 arg1 arg0 
g goo gar gaz
garg2 arg1 arg0 
f
farg2 arg1 arg0 
mcarifio
źródło
5
Zwróć uwagę, że itterowanie tablicy w ten sposób powoduje, że argumenty są w odwrotnej kolejności od wiersza poleceń.
Andrew Backer
96

Jeśli chcesz mieć swoje argumenty w stylu C (tablica argumentów + liczba argumentów), możesz użyć $@i $#.

$#podaje liczbę argumentów.
$@podaje wszystkie argumenty. Możesz przekształcić to w tablicę przezargs=("$@") .

Na przykład:

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

Zauważ, że w ${args[0]}rzeczywistości jest to pierwszy argument, a nie nazwa twojego skryptu.

stigi
źródło
5
To nie odpowiada na pytanie - chodzi o przekazanie argumentów wiersza poleceń do funkcji powłoki.
Cascabel
6
@Jefromi, właściwie, to doskonale odpowiada na pytanie. Możesz użyć argstablicy z wnętrza funkcji, jeśli wcześniej ją zainicjujesz, jak opisano.
vadipp
1
Uważam, że jest to o wiele czystsze niż iterowanie po argumentach.
Félix Gagnon-Grenier
1
To jest proste i łatwe. Świetna odpowiedź.
Wpisałeś
Jeszcze lepsze byłoby cytowanie echo "${args[0]} ${args[1]} ${args[2]}"lub argumenty podlegają rozszerzaniu nazw plików.
Benjamin W.
18
#!/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 $#

Edycja: zobacz mój komentarz do pytania

Ravi Vyas
źródło
16

Komentarz Raviego jest w istocie odpowiedzią. Funkcje przyjmują własne argumenty. Jeśli chcesz, aby były takie same jak argumenty wiersza poleceń, musisz je przekazać. W przeciwnym razie wyraźnie wywołujesz funkcję bez argumentów.

To powiedziawszy, możesz, jeśli chcesz, przechowywać argumenty wiersza poleceń w globalnej tablicy do użycia w innych funkcjach:

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

commandline_args=("$@")

my_function

Musisz uzyskać dostęp do argumentów wiersza poleceń poprzez commandline_argszmienną, nie $@, $1, $2, itd., Ale są one dostępne. Nie znam żadnego sposobu, aby przypisać bezpośrednio do tablicy argumentów, ale jeśli ktoś ją zna, proszę mnie oświecić!

Zwróć także uwagę na sposób, w jaki użyłem i zacytowałem $@- w ten sposób możesz upewnić się, że znaki specjalne (białe spacje) nie zostaną zepsute.

Cascabel
źródło
6
# 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
Peter Coulton
źródło
2

Można to również zrobić w ten sposób

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

Teraz wywołaj swój skrypt w stylu

./function_test.sh argument1 argument2
Vikash Singh
źródło
function print() {jest połączeniem dwóch różnych form deklaracji funkcji - function print {co jest starszą składnią ksh, która jest obsługiwana przez bash w celu zapewnienia kompatybilności wstecznej z pre-POSIX (czyli sprzed 1991 r.) ksh i print() {, która jest standaryzowana zgodnie z POSIX. Rozważ użycie jednej lub drugiej, aby uzyskać większą kompatybilność z innymi powłokami; zobacz także wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Możesz użyć słowa kluczowego shift (operator?), Aby je iterować. Przykład:

#!/bin/bash
function print()
{
    while [ $# -gt 0 ]
    do
        echo $1;
        shift 1;
    done
}
print $*;
Marin Alcaraz
źródło
2
function print() {jest połączeniem dwóch różnych form deklaracji funkcji - function print {co jest starszą składnią ksh, która jest obsługiwana przez bash w celu zapewnienia kompatybilności wstecznej z pre-POSIX (czyli sprzed 1991 r.) ksh i print() {, która jest standaryzowana zgodnie z POSIX. Rozważ użycie jednej lub drugiej, aby uzyskać większą kompatybilność z innymi powłokami; zobacz także wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Moje rozwiązanie:

Utwórz skrypt funkcji, który jest wywoływany wcześniej niż wszystkie inne funkcje bez przekazywania do niego żadnych argumentów, na przykład:

! / bin / bash

function init () {ORIGOPT = "- $ @ -"}

Następnie możesz wywołać init i użyć zmiennej ORIGOPT w razie potrzeby, jako plus, zawsze przypisuję nową zmienną i kopiuję zawartość ORIGOPT do moich nowych funkcji, dzięki czemu możesz mieć pewność, że nikt nie będzie go dotykał lub Zmień to.

Dodałem spacje i myślniki, aby ułatwić parsowanie go za pomocą 'sed -E', a także bash nie przekaże go jako odniesienia i sprawi, że ORIGOPT będzie rosnąć, gdy wywoływane są funkcje z większą liczbą argumentów.

cabonamigo
źródło