Cara membuat variabel dari subkulit yang tersedia di shell induk

11

Saya telah menulis skrip cepat dan kotor untuk mencatat waktu beberapa laporan dari layanan web:

BASE_URL='http://example.com/json/webservice/'
FIRST=1
FINAL=10000

for report_code in $(seq 1 $FINAL); do
  (time -p response=$(curl --write-out %{http_code} --silent -O ${BASE_URL}/${report_code}) ) 2> ${report_code}.time

  echo $response  # <------- this is out of scope!  How do I fix that?
  if [[ $response = '404' ]]; then
    echo "Deleting report # ${report_code}!"
    rm ${report_code}
  else
    echo "${report_code} seems to be good!"
  fi
done

Saya perlu membungkus timeperintah dalam sebuah subkulit sehingga saya dapat mengarahkan kembali outputnya, tetapi itu membuat nilai $responsetidak tersedia untuk shell induk. Bagaimana saya mengatasi masalah ini?

iconoclast
sumber

Jawaban:

11

Anda tidak dapat membawa nilai variabel dari subkulit ke induknya, tidak tanpa melakukan beberapa komunikasi rawan kesalahan dan komunikasi rumit.

Untungnya, Anda tidak perlu subkulit di sini. Pengalihan hanya membutuhkan pengelompokan perintah dengan { … }, bukan subkulit.

{ time -p response=$(curl --write-out '%{http_code}' --silent -O "${BASE_URL}/${report_code}"); } 2> "${report_code}.time"

(Jangan lupa tanda kutip ganda di sekitar substitusi variabel .)

Gilles 'SANGAT berhenti menjadi jahat'
sumber
itu lucu bahwa setiap bahasa pemrograman bisa melakukan itu. saya sudah menghabiskan 1 jam googling tanpa solusi di shell. Saya kecewa.
Ke Kra,
1
@ToKra No. Tidak ada bahasa pemrograman yang bisa melakukan ini. (Hampir) bahasa pemrograman apa pun dapat membawa nilai variabel dari subrutin atau blok instruksi ke induknya, dan itulah yang saya jelaskan dalam jawaban saya: gunakan pengelompokan perintah { … }daripada subkulit ( … ).
Gilles 'SANGAT berhenti menjadi jahat'
4

Rekan pengguna U&L: Sebelum menurunkan jawaban saya untuk menggunakan C-style with main()function, silakan kunjungi tautan ini: https://unix.stackexchange.com/a/313561/85039 Menggunakan fungsi utama dalam skrip adalah praktik umum, yang digunakan oleh banyak profesional di lapangan.


Seperti yang ditunjukkan Gilles, subkulit tidak dapat membuat variabel tersedia di luar lingkungan mereka. Tapi mari kita mendekati masalah ini dari sudut lain - jika Anda menulis skrip Anda dalam fungsi, dimungkinkan untuk mendeklarasikan variabel sebagai localdan yang dapat diedit.

Dari manual bash 4.3, localdeskripsi:

... Ketika lokal digunakan dalam suatu fungsi, itu menyebabkan nama variabel memiliki ruang lingkup yang terlihat terbatas pada fungsi itu dan anak-anaknya ...

Contoh:

#!/bin/bash

outter()
{
    for i in $(seq 1 3)
    do
        var=$i
    done
}

main()
{
    local var=0
    outter
    echo $var
}
main "$@"
$ ./testscript.sh                                                                                                        
3

Seperti yang Anda lihat setelah 3 iterasi dari fungsi looping, variabel dimodifikasi.

Sergiy Kolodyazhnyy
sumber
Hmm, perilaku tidak intuitif untuk programmer C. Saya biasanya berharap outteruntuk merujuk ke contoh global var.
Ruslan
Jawaban ini memiliki beberapa kekurangan. "$var"tidak diperlukan dalam panggilan keluar outter. Itu tidak melakukan apa-apa. Dan juga local var=0tidak melakukan apa pun; panggilan oufoutter tidak menimpa var, seperti yang Anda sebutkan.
Golar Ramblar
@GolarRamblar Saya telah menghapus "$var"sebagai argumen posisi outter; Agar adil, ini karena kebiasaan. Bisakah Anda menguraikan tentang local var=0 berpisah?
Sergiy Kolodyazhnyy