Saya ingin mengembalikan string dari fungsi Bash.
Saya akan menulis contoh di java untuk menunjukkan apa yang ingin saya lakukan:
public String getSomeString() {
return "tadaa";
}
String variable = getSomeString();
Contoh di bawah berfungsi dalam bash, tetapi apakah ada cara yang lebih baik untuk melakukan ini?
function getSomeString {
echo "tadaa"
}
VARIABLE=$(getSomeString)
string
bash
function
return-value
Tomas F
sumber
sumber
function funcName {
sintaksis pra-POSIX warisan diwarisi dari ksh awal (di mana ada perbedaan semantik yang bash tidak menghormati).funcName() {
, tanpafunction
, harus digunakan sebagai gantinya; lihat wiki.bash-hackers.org/scripting/obsoletefunction myFunction { blah; }
baik-baik saja; itufunction myFunction() { blah }
tidak baik, yaitu penggunaan tanda kurung dengan fungsi kata kunci.Jawaban:
Tidak ada cara yang lebih baik yang saya tahu. Bash hanya tahu kode status (bilangan bulat) dan string yang ditulis ke stdout.
sumber
somefunction && echo 'success'
). Jika Anda berpikir tentang fungsi seperti perintah lain, itu masuk akal; perintah tidak "mengembalikan" apa pun yang keluar selain dari kode status, tetapi perintah tersebut dapat menampilkan hal-hal sementara yang dapat Anda tangkap.Anda bisa meminta fungsi mengambil variabel sebagai argumen pertama dan memodifikasi variabel dengan string yang ingin Anda kembalikan.
Mencetak "foo bar rab oof".
Edit : menambahkan kutipan di tempat yang sesuai untuk memungkinkan spasi putih dalam string untuk mengatasi komentar @Luca Borrione.
Sunting : Sebagai demonstrasi, lihat program berikut. Ini adalah solusi tujuan umum: bahkan memungkinkan Anda untuk menerima string ke variabel lokal.
Ini mencetak:
Mengedit : menunjukkan bahwa nilai variabel asli yang tersedia di fungsi, seperti yang tidak benar dikritik oleh @Xichen Li dalam komentar.
Ini menghasilkan:
sumber
fgm
jawaban yang ditulis dengan cara yang disederhanakan? Ini tidak akan berfungsi jika stringfoo
berisi spasi putih, sedangkan yangfgm
satu akan .. seperti yang ditampilkan.\$$1
. Jika Anda mencari sesuatu yang berbeda, beri tahu saya.printf '%q' "$var"
. % q adalah string format untuk pelarian shell. Kemudian hanya lulus mentah.Semua jawaban di atas mengabaikan apa yang telah dinyatakan di halaman manual bash.
Kode contoh
Dan output
Juga di bawah pdksh dan ksh script ini melakukan hal yang sama!
sumber
Bash, sejak versi 4.3, Februari 2014 (?), Memiliki dukungan eksplisit untuk variabel referensi atau referensi nama (namerefs), di luar "eval", dengan kinerja manfaat dan efek tipuan yang sama, dan yang mungkin lebih jelas dalam skrip Anda dan juga lebih sulit untuk "lupa untuk 'eval' dan harus memperbaiki kesalahan ini":
dan juga:
Misalnya ( EDIT 2 : (terima kasih Ron) namespaced (diawali) nama variabel fungsi-internal, untuk meminimalkan benturan variabel eksternal, yang akhirnya harus menjawab dengan benar, masalah yang diangkat dalam komentar oleh Karsten):
dan menguji contoh ini:
Perhatikan bahwa bash "menyatakan" builtin, ketika digunakan dalam suatu fungsi, menjadikan variabel yang dideklarasikan "lokal" secara default, dan "-n" juga dapat digunakan dengan "lokal".
Saya lebih suka membedakan variabel "mendeklarasikan penting" dari variabel "membosankan lokal", jadi menggunakan "menyatakan" dan "lokal" dengan cara ini bertindak sebagai dokumentasi.
EDIT 1 - (Tanggapan terhadap komentar di bawah oleh Karsten) - Saya tidak dapat menambahkan komentar di bawah ini lagi, tetapi komentar Karsten membuat saya berpikir, jadi saya melakukan tes berikut yang BEKERJA HALUS, AFAICT - Karsten jika Anda membaca ini, berikan set yang tepat langkah uji dari baris perintah, menunjukkan masalah yang Anda asumsikan ada, karena langkah-langkah berikut ini berfungsi dengan baik:
(Saya menjalankan ini sekarang, setelah menempelkan fungsi di atas ke dalam istilah bash - seperti yang Anda lihat, hasilnya bekerja dengan baik.)
sumber
declare
membuat variabel lokal di dalam fungsi (info itu tidak diberikan olehhelp declare
): "... Ketika digunakan dalam suatu fungsi, deklarasikan dan ketik setel setiap nama lokal, seperti dengan perintah lokal, kecuali - opsi g disediakan ... "K=$1; V=$2; eval "$A='$V'";
, tetapi satu kesalahan (misalnya parameter kosong atau dihilangkan), dan itu akan lebih berbahaya. @zenaan masalah yang diangkat oleh @Karsten berlaku jika Anda memilih "message" sebagai nama variabel kembali, alih-alih "ret".Seperti bstpierre di atas, saya menggunakan dan merekomendasikan penggunaan variabel output penamaan eksplisit:
Perhatikan penggunaan mengutip $. Ini akan menghindari menafsirkan konten
$result
sebagai karakter khusus shell. Saya telah menemukan bahwa ini adalah urutan besarnya lebih cepat daripadaresult=$(some_func "arg1")
ungkapan menangkap gema. Perbedaan kecepatan tampaknya bahkan lebih terkenal menggunakan bash pada MSYS di mana stdout menangkap dari panggilan fungsi hampir menjadi bencana besar.Tidak apa-apa mengirim variabel lokal karena penduduk lokal secara dinamis dicakup dalam bash:
sumber
echo
dalam suatu fungsi, dikombinasikan dengan penggantian perintah!Anda juga dapat menangkap output fungsi:
Terlihat aneh, tetapi lebih baik daripada menggunakan variabel global IMHO. Melewati parameter berfungsi seperti biasa, cukup taruh di dalam kawat gigi atau backtick.
sumber
Solusi yang paling mudah dan kuat adalah dengan menggunakan substitusi perintah, seperti yang ditulis orang lain:
Kelemahannya adalah kinerja karena ini membutuhkan proses yang terpisah.
Teknik lain yang disarankan dalam topik ini, yaitu meneruskan nama variabel untuk ditetapkan sebagai argumen, memiliki efek samping, dan saya tidak akan merekomendasikannya dalam bentuk dasarnya. Masalahnya adalah bahwa Anda mungkin perlu beberapa variabel dalam fungsi untuk menghitung nilai kembali, dan mungkin saja nama variabel yang dimaksudkan untuk menyimpan nilai pengembalian akan mengganggu salah satu dari mereka:
Anda mungkin, tentu saja, tidak mendeklarasikan variabel internal dari fungsi sebagai lokal, tetapi Anda benar-benar harus selalu melakukannya karena jika tidak, Anda mungkin, secara tidak sengaja menimpa variabel yang tidak terkait dari ruang lingkup induk jika ada satu dengan nama yang sama .
Salah satu solusi yang mungkin adalah deklarasi eksplisit dari variabel yang dikirimkan sebagai global:
Jika nama "x" dilewatkan sebagai argumen, baris kedua dari badan fungsi akan menimpa deklarasi lokal sebelumnya. Tetapi nama-nama itu sendiri mungkin masih mengganggu, jadi jika Anda berniat untuk menggunakan nilai yang sebelumnya disimpan dalam variabel yang dikirimkan sebelum menulis nilai kembali di sana, perlu diketahui bahwa Anda harus menyalinnya ke variabel lokal lain di awal; jika tidak hasilnya akan tidak dapat diprediksi! Selain itu, ini hanya akan berfungsi dalam versi BASH terbaru, yaitu 4.2. Lebih banyak kode portabel mungkin menggunakan konstruksi kondisional eksplisit dengan efek yang sama:
Mungkin solusi yang paling elegan adalah hanya mencadangkan satu nama global untuk nilai-nilai pengembalian fungsi dan menggunakannya secara konsisten di setiap fungsi yang Anda tulis.
sumber
eval
maupundeclare -n
. Solusi untuk memiliki nama variabel tunggal khusus sepertiresult
untuk semua parameter output tampaknya satu-satunya solusi yang tidak memerlukan fungsi untuk mengetahui semua penelepon itu untuk menghindari konflik.Seperti disebutkan sebelumnya, cara "benar" untuk mengembalikan string dari suatu fungsi adalah dengan substitusi perintah. Jika fungsi tersebut juga perlu di-output ke konsol (seperti @Mani menyebutkan di atas), buat fd sementara di awal fungsi dan arahkan ke konsol. Tutup fd sementara sebelum mengembalikan string Anda.
mengeksekusi skrip tanpa params menghasilkan ...
Semoga ini bisa membantu orang
-Andy
sumber
3>&1
di bagian atas skrip, lalu memanipulasi&1
&3
dan placeholder lain&4
dalam fungsi. Jelek semua, meskipun.Anda bisa menggunakan variabel global:
Ini memberi
sumber
Untuk mengilustrasikan komentar saya pada jawaban Andy, dengan manipulasi deskriptor file tambahan untuk menghindari penggunaan
/dev/tty
:Tapi tetap saja jahat.
sumber
Cara Anda memilikinya adalah satu-satunya cara untuk melakukan ini tanpa melanggar ruang lingkup. Bash tidak memiliki konsep tipe pengembalian, cukup kode keluar dan deskriptor file (stdin / out / err, dll)
sumber
Mengatasi kepala Vicky Ronnen , mempertimbangkan kode berikut:
akan memberi
Mungkin skenario normal adalah dengan menggunakan sintaks yang digunakan dalam
test_inside_a_func
fungsi, sehingga Anda dapat menggunakan kedua metode di sebagian besar kasus, meskipun menangkap output adalah metode yang lebih aman selalu bekerja dalam situasi apa pun, meniru nilai kembali dari fungsi yang Anda bisa temukan dalam bahasa lain, sebagaimanaVicky Ronnen
ditunjukkan dengan benar.sumber
Semua opsi sudah disebutkan, saya kira. Memilih satu dapat datang ke masalah gaya terbaik untuk aplikasi khusus Anda, dan dalam nada itu, saya ingin menawarkan satu gaya tertentu yang saya temukan berguna. Dalam bash, variabel dan fungsi tidak berada dalam ruang nama yang sama. Jadi, memperlakukan variabel dengan nama yang sama dengan nilai fungsi adalah konvensi yang saya temukan meminimalkan bentrokan nama dan meningkatkan keterbacaan, jika saya menerapkannya dengan ketat. Contoh dari kehidupan nyata:
Dan, contoh penggunaan fungsi-fungsi tersebut:
Seperti yang Anda lihat, status pengembalian ada untuk Anda gunakan saat Anda membutuhkannya, atau abaikan jika tidak. Variabel "dikembalikan" juga dapat digunakan atau diabaikan, tetapi tentu saja hanya setelah fungsi dipanggil.
Tentu saja, ini hanya sebuah konvensi. Anda bebas untuk gagal mengatur nilai terkait sebelum kembali (karena itu konvensi saya untuk selalu membatalkannya di awal fungsi) atau menginjak nilainya dengan memanggil fungsi lagi (mungkin secara tidak langsung). Tetap saja, ini adalah konvensi yang menurut saya sangat berguna jika saya menggunakan banyak fungsi bash.
Bertolak belakang dengan sentimen bahwa ini adalah tanda yang semestinya misalnya "pindah ke perl", filosofi saya adalah bahwa konvensi selalu penting untuk mengelola kompleksitas bahasa apa pun.
sumber
Anda dapat
echo
sebuah string, tetapi menangkapnya dengan memipet (|
) fungsi ke sesuatu yang lain.Anda dapat melakukannya dengan
expr
, meskipun ShellCheck melaporkan penggunaan ini sudah usang.sumber
myfunc | read OUTPUT ; echo $OUTPUT
tidak menghasilkan apa-apa.myfunc | ( read OUTPUT; echo $OUTPUT )
tidak mendapatkan nilai yang diharapkan dan mengklarifikasi apa yang terjadi di sisi kanan. Tapi tentu saja OUTPUT tidak tersedia di tempat yang Anda butuhkan ...Mereka masalah utama dari setiap skema 'bernama variabel keluaran' di mana penelepon dapat meneruskan nama variabel (apakah menggunakan
eval
ataudeclare -n
) tidak sengaja alias, yaitu bentrokan nama: Dari sudut pandang enkapsulasi, sangat mengerikan untuk tidak dapat menambah atau mengganti nama variabel lokal dalam suatu fungsi tanpa memeriksa SEMUA penelepon fungsi terlebih dahulu untuk memastikan mereka tidak ingin memberikan nama yang sama dengan parameter output. (Atau ke arah lain, saya tidak ingin harus membaca sumber fungsi yang saya panggil hanya untuk memastikan parameter output yang ingin saya gunakan bukan lokal dalam fungsi itu.)Satu-satunya cara mengatasinya adalah dengan menggunakan variabel output khusus seperti
REPLY
(seperti yang disarankan oleh Evi1M4chine ) atau konvensi seperti yang disarankan oleh Ron Burk .Namun, dimungkinkan untuk memiliki fungsi menggunakan variabel keluaran tetap secara internal , dan kemudian menambahkan gula di atasnya untuk menyembunyikan fakta ini dari pemanggil , seperti yang telah saya lakukan dengan
call
fungsi pada contoh berikut. Anggap ini bukti konsep, tetapi poin kuncinya adalahREPLY
, dan juga dapat mengembalikan kode keluar seperti biasaREPLY
(lihatwrapper
contoh). Kode keluar dari fungsi dilewati, jadi menggunakannya dalam misalnya aif
atauwhile
atau konstruksi serupa berfungsi seperti yang diharapkan.Alasan ini berfungsi adalah karena
call
fungsi itu sendiri tidak memiliki penduduk setempat dan tidak menggunakan variabel selainREPLY
, menghindari potensi bentrokan nama. Pada titik di mana nama variabel output yang ditentukan pemanggil ditetapkan, kita secara efektif berada dalam ruang lingkup pemanggil (secara teknis dalam lingkupcall
fungsi yang identik ), daripada dalam lingkup fungsi yang dipanggil.Keluaran:
sumber
bash pattern untuk mengembalikan objek nilai skalar dan array :
definisi
doa
sumber
Dalam program saya, berdasarkan konvensi, ini adalah untuk apa
$REPLY
variabel yang sudah ada sebelumnya , yangread
digunakan untuk tujuan yang tepat.Ini
echo
esTetapi untuk menghindari konflik, variabel global lainnya akan dilakukan.
Jika itu tidak cukup, saya sarankan solusi Markarian451 .
sumber
sumber