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 $*

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 

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.


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


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.


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

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

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 $*;

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.