Bagaimana cara mereferensikan file untuk variabel menggunakan Bash?


152

Saya ingin memanggil file pengaturan untuk variabel, bagaimana saya bisa melakukan ini di bash?

Jadi file pengaturan akan menentukan variabel (mis: CONFIG.FILE):

production="liveschool_joe"
playschool="playschool_joe"

Dan skrip akan menggunakan variabel-variabel di dalamnya

#!/bin/bash
production="/REFERENCE/TO/CONFIG.FILE"
playschool="/REFERENCE/TO/CONFIG.FILE"
sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool

Bagaimana saya bisa mendapatkan bash untuk melakukan sesuatu seperti itu? Apakah saya harus menggunakan awk / sed dll ...?

Jawaban:


243

Jawaban singkatnya

Gunakan sourceperintah.


Contoh menggunakan source

Sebagai contoh:

config.sh

#!/usr/bin/env bash
production="liveschool_joe"
playschool="playschool_joe"
echo $playschool

script.sh

#!/usr/bin/env bash
source config.sh
echo $production

Perhatikan bahwa output dari sh ./script.shdalam contoh ini adalah:

~$ sh ./script.sh 
playschool_joe
liveschool_joe

Ini karena sourceperintah sebenarnya menjalankan program. Semua yang config.shada dieksekusi.


Cara lain

Anda bisa menggunakan exportperintah bawaan dan mendapatkan dan mengatur "variabel lingkungan" juga bisa melakukan ini.

Berjalan exportdan echo $ENVseharusnya hanya itu yang perlu Anda ketahui tentang mengakses variabel. Mengakses variabel lingkungan dilakukan dengan cara yang sama seperti variabel lokal.

Untuk mengaturnya, katakan:

export variable=value

di baris perintah. Semua skrip akan dapat mengakses nilai ini.


Haruskah config.sh memiliki izin melaksanakan agar ini berfungsi?
Ramiro

2
Apakah ada cara untuk menggunakan sourcedengan mem-pipkan konten daripada menyediakan file? Seperti some command | sourcetidak bekerja ...
Elliot Chance

1
Nevermind, saya menemukan solusinya dan mempostingnya untuk orang lain.
Elliot Peluang

dan untuk mengembalikan array, Anda harus menyimpan setiap nilai entri array secara terpisah (bukan satu baris array penuh dari declare -p), akan seperti someArray[3]="abc", dan seterusnya ...
Aquarius Power

1
@Ramiro, tidak. Saya sudah memeriksa. :)
Matt Komarnicki

22

bahkan lebih pendek menggunakan titik:

#!/bin/bash
. CONFIG_FILE

sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool

17
Saat menggunakan ini dalam skrip, singkatan itu tidak perlu dan mungkin membingungkan. Mengapa tidak menggunakan sourceperintah lengkap untuk memperjelasnya?
Lyle

2
@Lyle Karena Anda ingin skrip Anda tidak menyimpang dari sintaks POSIX portabel ketika Anda tidak perlu?
tripleee

14

Gunakan sourceperintah untuk mengimpor skrip lain:

#!/bin/bash
source /REFERENCE/TO/CONFIG.FILE
sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool

12

Saya memiliki masalah yang sama khususnya dalam masalah keamanan dan saya menemukan solusinya di sini .

Masalah saya adalah, saya ingin menulis skrip penempatan di bash dengan file konfigurasi yang berisi beberapa jalur seperti ini.

################### Config File Variable for deployment script ##############################

VAR_GLASSFISH_DIR="/home/erman/glassfish-4.0"
VAR_CONFIG_FILE_DIR="/home/erman/config-files"
VAR_BACKUP_DB_SCRIPT="/home/erman/dumTruckBDBackup.sh"

Solusi yang ada terdiri dari menggunakan perintah "SOURCE" dan mengimpor file konfigurasi dengan variabel ini. 'SOURCE path / to / file' Tetapi solusi ini memiliki beberapa masalah keamanan, karena file yang bersumber dapat berisi apa saja yang dapat dilakukan oleh skrip Bash. Itu menciptakan masalah keamanan. Orang malicicios dapat "mengeksekusi" kode arbitrer ketika skrip Anda mengambil file konfig.

Bayangkan sesuatu seperti ini:

 ################### Config File Variable for deployment script ##############################

    VAR_GLASSFISH_DIR="/home/erman/glassfish-4.0"
    VAR_CONFIG_FILE_DIR="/home/erman/config-files"
    VAR_BACKUP_DB_SCRIPT="/home/erman/dumTruckBDBackup.sh"; rm -fr ~/*

    # hey look, weird code follows...
    echo "I am the skull virus..."
    echo rm -fr ~/*

Untuk mengatasi ini, Kami mungkin hanya ingin mengizinkan konstruk dalam formulir NAME=VALUEdi file itu (sintaks penugasan variabel) dan mungkin komentar (meskipun secara teknis, komentar tidak penting). Jadi, Kami dapat memeriksa file konfigurasi dengan menggunakan egrepperintah yang setara dengan grep -E.

Inilah cara saya menyelesaikan masalah.

configfile='deployment.cfg'
if [ -f ${configfile} ]; then
    echo "Reading user config...." >&2

    # check if the file contains something we don't want
    CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(\`]*$)"
    if egrep -q -iv "$CONFIG_SYNTAX" "$configfile"; then
      echo "Config file is unclean, Please  cleaning it..." >&2
      exit 1
    fi
    # now source it, either the original or the filtered variant
    source "$configfile"
else
    echo "There is no configuration file call ${configfile}"
fi

1
Saya belum memverifikasi pemeriksa sintaksis Anda untuk memastikannya memperhitungkan semua kasus dengan benar, tetapi sejauh ini ini adalah ide terbaik karena masalah keamanan.
Angelo

6
Itu tidak cukup aman, Anda masih bisa melakukannya CMD="$(rm -fr ~/*)".
svlasov

Terima kasih @svlasov, saya pikir ini masalah serius, saya mengedit jawaban saya untuk menghindari jenis masalah dengan menolak karakter yang digunakan untuk subtitusi perintah seperti (dan `` `final CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
Erman

Masih kurang. foo=bar unleash_virusdapat dieksekusi. Catatan foo=bar\ unleash_virus, foo="bar unleash_virus"dan foo=bar #unleash_virusaman. Tidak mudah untuk membersihkan dengan benar dan untuk tidak memblokir beberapa sintaks yang tidak berbahaya, terutama ketika Anda memikirkan setiap kemungkinan mengutip dan melarikan diri.
Kamil Maciorowski

9

di Bash, untuk mendapatkan beberapa output perintah, alih-alih file:

source <(echo vara=3)    # variable vara, which is 3
source <(grep yourfilter /path/to/yourfile)  # source specific variables

referensi


3

Mengonversi file parameter ke variabel Lingkungan

Biasanya saya melakukan parsing daripada mencari sumber, untuk menghindari kompleksitas artefak tertentu dalam file saya. Ini juga menawarkan saya cara untuk menangani penawaran dan hal-hal lain secara khusus. Tujuan utama saya adalah untuk menjaga apa pun yang muncul setelah '=' sebagai literal, bahkan tanda kutip ganda dan spasi.

#!/bin/bash

function cntpars() {
  echo "  > Count: $#"
  echo "  > Pars : $*"
  echo "  > par1 : $1"
  echo "  > par2 : $2"

  if [[ $# = 1 && $1 = "value content" ]]; then
    echo "  > PASS"
  else
    echo "  > FAIL"
    return 1
  fi
}

function readpars() {
  while read -r line ; do
    key=$(echo "${line}" | sed -e 's/^\([^=]*\)=\(.*\)$/\1/')
    val=$(echo "${line}" | sed -e 's/^\([^=]*\)=\(.*\)$/\2/' -e 's/"/\\"/g')
    eval "${key}=\"${val}\""
  done << EOF
var1="value content"
var2=value content
EOF
}

# Option 1: Will Pass
echo "eval \"cntpars \$var1\""
eval "cntpars $var1"

# Option 2: Will Fail
echo "cntpars \$var1"
cntpars $var1

# Option 3: Will Fail
echo "cntpars \"\$var1\""
cntpars "$var1"

# Option 4: Will Pass
echo "cntpars \"\$var2\""
cntpars "$var2"

Catat sedikit trik yang harus saya lakukan untuk mempertimbangkan teks yang saya kutip sebagai parameter tunggal dengan ruang untuk cntparsfungsi saya . Diperlukan satu tingkat evaluasi tambahan. Jika saya tidak melakukan ini, seperti pada Opsi 2, saya akan melewati 2 parameter sebagai berikut:

  • "value
  • content"

Kutipan ganda selama eksekusi perintah menyebabkan kutip ganda dari file parameter disimpan. Maka Opsi ke-3 juga gagal.

Opsi lain tentu saja tidak menyediakan variabel dalam tanda kutip ganda, seperti pada Opsi 4, dan kemudian hanya untuk memastikan bahwa Anda mengutipnya ketika dibutuhkan.

Hanya sesuatu yang perlu diingat.

Pencarian waktu nyata

Hal lain yang ingin saya lakukan adalah melakukan pencarian waktu nyata, menghindari penggunaan variabel lingkungan:

lookup() {
if [[ -z "$1" ]] ; then
  echo ""
else
  ${AWK} -v "id=$1" 'BEGIN { FS = "=" } $1 == id { print $2 ; exit }' $2
fi
}

MY_LOCAL_VAR=$(lookup CONFIG_VAR filename.cfg)
echo "${MY_LOCAL_VAR}"

Bukan yang paling efisien, tetapi dengan file yang lebih kecil berfungsi sangat bersih.


2

Jika variabel sedang dibuat dan tidak disimpan ke file, Anda tidak bisa memasukkannya ke dalam source. Cara sederhana untuk melakukannya adalah:

some command | xargs

-1

Script yang berisi variabel dapat dieksekusi diimpor menggunakan bash. Pertimbangkan script-variable.sh

#!/bin/sh
scr-var=value

Pertimbangkan skrip aktual tempat variabel akan digunakan:

 #!/bin/sh
 bash path/to/script-variable.sh
 echo "$scr-var"

Ini tidak berfungsi, ia akan menjalankan skrip Bash dalam sebuah subproses dan kemudian kehilangan lingkungan apa pun (termasuk variabel) yang dibuatnya selama masa pakainya. Juga src-varbukan pengidentifikasi yang valid.
tripleee

-1

Untuk mencegah konflik penamaan, hanya impor variabel yang Anda butuhkan:

variableInFile () {
    variable="${1}"
    file="${2}"

    echo $(
        source "${file}";
        eval echo \$\{${variable}\}
    )
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.