Bagaimana cara mengakses argumen baris perintah pemanggil di dalam suatu fungsi?

97

Saya mencoba untuk menulis fungsi di bash yang akan mengakses argumen baris perintah skrip, tetapi mereka diganti dengan argumen posisi ke fungsi tersebut. Apakah ada cara agar fungsi mengakses argumen baris perintah jika tidak diteruskan secara eksplisit?

# 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
sumber
3
Saya agak bingung, Anda ingin berdebat tanpa melewati mereka?
Ravi Vyas
4
Ya, intinya adalah untuk mendapatkan terlalu banyak argumen baris perintah dari dalam suatu fungsi tanpa meneruskannya sebagai argumen fungsional. Ini ada hubungannya dengan situasi penanganan kesalahan di mana saya ingin melakukan penanganan kesalahan berdasarkan argumen baris perintah secara independen dari argumen yang diteruskan ke fungsi.
DonGar
FYI, $*sangat buggy - itu akan berubah ./yourScript "first argument" "second argument"menjadi ./yourscript "first" "argument" "second" "argument", atau berubah ./yourscript '*.txt'menjadi sesuatu seperti ./yourscript one.txt two.txtmeskipun ada tanda kutip.
Charles Duffy

Jawaban:

46

Saya membaca manual ref bash mengatakan hal ini ditangkap di BASH_ARGV, meskipun berbicara banyak tentang "tumpukan".

#!/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

Simpan di 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
sumber
5
Perhatikan bahwa mengulang array seperti itu menyebabkan args berada dalam urutan terbalik dari baris perintah.
Andrew Backer
93

Jika Anda ingin memiliki gaya argumen C (array argumen + jumlah argumen), Anda dapat menggunakan $@dan $#.

$#memberi Anda jumlah argumen.
$@memberi Anda semua argumen. Anda dapat mengubahnya menjadi array dengan args=("$@").

Jadi contohnya:

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

Perhatikan bahwa di sini ${args[0]}sebenarnya adalah argumen pertama dan bukan nama skrip Anda.

stigi
sumber
5
Ini tidak menjawab pertanyaan - ini menanyakan tentang meneruskan argumen baris perintah bersama ke fungsi shell.
Cascabel
6
@Jefromi, sebenarnya, ini menjawab pertanyaan dengan sempurna. Anda dapat menggunakan argsarray dari dalam fungsi, jika Anda menginisialisasi sebelumnya seperti yang dijelaskan.
vadipp
1
Saya menemukan ini jauh lebih bersih daripada mengulang-ulang argumen.
Félix Gagnon-Grenier
1
Ini sederhana dan mudah. Jawaban yang bagus. Anda memposting ini lebih dari 7 tahun yang lalu, jadi halo dari masa depan: Juli 2017
SDsolar
Bahkan lebih baik mengutip seperti echo "${args[0]} ${args[1]} ${args[2]}", atau argumen tunduk pada perluasan nama file.
Benjamin W.
17
#!/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: silakan lihat komentar saya di pertanyaan

Ravi Vyas
sumber
16

Komentar Ravi pada dasarnya adalah jawabannya. Fungsi mengambil argumennya sendiri. Jika Anda ingin agar sama dengan argumen baris perintah, Anda harus meneruskannya. Jika tidak, Anda jelas memanggil fungsi tanpa argumen.

Yang mengatakan, Anda bisa jika Anda suka menyimpan argumen baris perintah dalam larik global untuk digunakan dalam fungsi lain:

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

commandline_args=("$@")

my_function

Anda harus mengakses argumen baris perintah melalui commandline_argsvariabel, tidak $@, $1, $2, dll, tapi mereka tersedia. Saya tidak mengetahui cara untuk menetapkan langsung ke array argumen, tetapi jika seseorang mengetahuinya, tolong beri tahu saya!

Juga, perhatikan cara saya menggunakan dan mengutip $@- ini adalah cara Anda memastikan karakter khusus (spasi) tidak kacau.

Bertingkat
sumber
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
sumber
2

Seseorang dapat melakukannya seperti ini juga

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

Sekarang panggil skrip Anda seperti

./function_test.sh argument1 argument2
Vikash Singh
sumber
function print() {adalah campuran antara dua bentuk deklarasi fungsi yang berbeda - function print {, yang merupakan sintaks ksh lama yang didukung bash untuk kompatibilitas mundur dengan pra-POSIX (artinya, pra-1991) ksh, dan print() {, yang berstandar POSIX. Pertimbangkan untuk menggunakan satu atau yang lain untuk kompatibilitas yang lebih luas dengan cangkang lain; lihat juga wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Anda dapat menggunakan kata kunci shift (operator?) Untuk mengulanginya. Contoh:

#!/bin/bash
function print()
{
    while [ $# -gt 0 ]
    do
        echo $1;
        shift 1;
    done
}
print $*;
Marin Alcaraz
sumber
2
function print() {adalah campuran antara dua bentuk deklarasi fungsi yang berbeda - function print {, yang merupakan sintaks ksh lama yang didukung bash untuk kompatibilitas mundur dengan pra-POSIX (artinya, pra-1991) ksh, dan print() {, yang berstandar POSIX. Pertimbangkan untuk menggunakan satu atau yang lain untuk kompatibilitas yang lebih luas dengan cangkang lain; lihat juga wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Solusi saya:

Buat skrip fungsi yang dipanggil lebih awal dari semua fungsi lainnya tanpa memberikan argumen apa pun, seperti ini:

! / bin / bash

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

Selain itu, Anda dapat memanggil init dan menggunakan ORIGOPT var sesuai kebutuhan, sebagai nilai tambah, saya selalu menetapkan var baru dan menyalin konten ORIGOPT di fungsi baru saya, dengan begitu Anda dapat memastikan bahwa tidak ada yang akan menyentuhnya atau ubahlah.

Saya menambahkan spasi dan tanda hubung untuk mempermudah penguraiannya dengan 'sed -E' juga bash tidak akan meneruskannya sebagai referensi dan membuat ORIGOPT bertambah karena fungsi dipanggil dengan lebih banyak argumen.

cabonamigo.dll
sumber