Làm thế nào để tham chiếu một tệp cho các biến bằng Bash?


151

Tôi muốn gọi một tệp cài đặt cho một biến, làm thế nào tôi có thể làm điều này trong bash?

Vì vậy, tệp cài đặt sẽ xác định các biến (ví dụ: CONFIG.FILE):

production="liveschool_joe"
playschool="playschool_joe"

Và tập lệnh sẽ sử dụng các biến đó trong đó

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

Làm thế nào tôi có thể nhận được bash để làm một cái gì đó như thế? Tôi sẽ phải sử dụng awk / sed, v.v ...?

Câu trả lời:


241

Câu trả lời ngắn

Sử dụng sourcelệnh.


Một ví dụ sử dụng source

Ví dụ:

cấu hình

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

script.sh

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

Lưu ý rằng đầu ra từ sh ./script.shtrong ví dụ này là:

~$ sh ./script.sh 
playschool_joe
liveschool_joe

Điều này là do sourcelệnh thực sự chạy chương trình. Tất cả mọi thứ trong config.shđược thực hiện.


Cách khác

Bạn có thể sử dụng exportlệnh tích hợp và nhận và thiết lập "biến môi trường" cũng có thể thực hiện việc này.

Chạy exportecho $ENVnên là tất cả những gì bạn cần biết về việc truy cập các biến. Truy cập các biến môi trường được thực hiện giống như một biến cục bộ.

Để đặt chúng, hãy nói:

export variable=value

tại dòng lệnh. Tất cả các tập lệnh sẽ có thể truy cập giá trị này.


Phải config.sh có quyền thực thi để làm việc này?
Ramiro

2
Có cách nào để sử dụng sourcebằng cách đặt đường ống trong nội dung thay vì cung cấp một tệp không? Giống như some command | sourcekhông hoạt động ...
Elliot Chance

1
Nevermind, tôi tìm thấy giải pháp và đăng nó cho người khác.
Cơ hội Elliot

và để khôi phục các mảng, bạn phải lưu trữ từng giá trị mục nhập mảng (không phải là dòng đơn mảng đầy đủ từ declare -p), sẽ như vậy someArray[3]="abc", v.v ...
Aquarius Power

1
@Ramiro không có. Tôi đã kiểm tra. :)
Matt Komarnicki

22

thậm chí ngắn hơn bằng cách sử dụng dấu chấm:

#!/bin/bash
. CONFIG_FILE

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

17
Khi sử dụng điều này trong một kịch bản, tốc ký là không cần thiết và có thể gây nhầm lẫn. Tại sao không sử dụng sourcelệnh đầy đủ để làm cho nó rõ ràng?
Lyle

2
@Lyle Vì bạn muốn tập lệnh của mình không bị lệch một cách vô cớ khỏi cú pháp POSIX di động khi bạn không phải làm thế?
tripleee

14

Sử dụng sourcelệnh để nhập các tập lệnh khác:

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

Tôi có cùng một vấn đề đặc biệt trong vấn đề bảo mật và tôi đã tìm thấy giải pháp ở đây .

Vấn đề của tôi là, tôi muốn viết một kịch bản triển khai trong bash với một tệp cấu hình có nội dung một số đường dẫn như thế này.

################### 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"

Một giải pháp hiện có bao gồm sử dụng lệnh "SOURCE" và nhập tệp cấu hình với các biến này. 'Đường dẫn SOURCE / đến / tệp' Nhưng giải pháp này có một số vấn đề bảo mật, vì tệp có nguồn gốc có thể chứa bất cứ thứ gì mà tập lệnh Bash có thể. Điều đó tạo ra các vấn đề bảo mật. Một người malicicios có thể "thực thi" mã tùy ý khi tập lệnh của bạn đang tìm nguồn cung cấp tệp cấu hình của nó.

Hãy tưởng tượng một cái gì đó như thế này:

 ################### 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 ~/*

Để giải quyết vấn đề này, chúng tôi có thể chỉ muốn cho phép các cấu trúc trong biểu mẫu NAME=VALUEtrong tệp đó (cú pháp gán biến) và có thể nhận xét (mặc dù về mặt kỹ thuật, các nhận xét là không quan trọng). Vì vậy, chúng ta có thể kiểm tra tệp cấu hình bằng cách sử dụng egreplệnh tương đương vớigrep -E .

Đây là cách tôi đã giải quyết vấn đề.

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
Tôi chưa xác minh trình kiểm tra cú pháp của bạn để đảm bảo rằng nó giải thích chính xác cho tất cả các trường hợp, nhưng đây là ý tưởng tốt nhất vì vấn đề bảo mật.
Angelo

6
Điều đó không đủ an toàn, bạn vẫn có thể làm CMD="$(rm -fr ~/*)".
Svlasov

Cảm ơn @svlasov, tôi nghĩ đó là một vấn đề nghiêm trọng, tôi chỉnh sửa câu trả lời của mình để tránh loại vấn đề đó bằng cách từ chối các ký tự được sử dụng để trừ lệnh như (và `` `trận chung kết CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
Erman

Vẫn không đủ. foo=bar unleash_viruscó thể được thực thi. Lưu ý foo=bar\ unleash_virus, foo="bar unleash_virus"foo=bar #unleash_virusan toàn. Thật không dễ dàng để vệ sinh đúng cách và không chặn một số cú pháp vô hại, đặc biệt là khi bạn nghĩ về mọi trích dẫn có thể có và thoát ra.
Kamil Maciorowski

9

trong Bash, để lấy một số đầu ra của lệnh, thay vì một tệp:

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

tài liệu tham khảo


3

Chuyển đổi tệp tham số thành các biến môi trường

Thông thường tôi đi về phân tích cú pháp thay vì tìm nguồn cung ứng, để tránh sự phức tạp của một số tạo phẩm nhất định trong tệp của tôi. Nó cũng cung cấp cho tôi những cách để đặc biệt xử lý báo giá và những thứ khác. Mục đích chính của tôi là giữ bất cứ điều gì xuất hiện sau '=' dưới dạng nghĩa đen, thậm chí là dấu ngoặc kép và dấu cách.

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

Lưu ý mẹo nhỏ tôi phải làm để coi văn bản được trích dẫn của tôi là một tham số duy nhất có khoảng trống cho cntparschức năng của tôi . Có thêm một mức đánh giá cần thiết. Nếu tôi không làm điều này, như trong Tùy chọn 2, tôi đã chuyển 2 tham số như sau:

  • "value
  • content"

Trích dẫn kép trong khi thực hiện lệnh làm cho dấu ngoặc kép từ tệp tham số được giữ. Do đó, lựa chọn thứ 3 cũng thất bại.

Tất nhiên, tùy chọn khác sẽ chỉ đơn giản là không cung cấp các biến trong dấu ngoặc kép, như trong Tùy chọn 4, và sau đó chỉ để đảm bảo rằng bạn trích dẫn chúng khi cần.

Chỉ là một thứ để ghi nhớ trong đầu.

Tra cứu thời gian thực

Một điều khác tôi muốn làm là thực hiện tra cứu thời gian thực, tránh sử dụng các biến môi trường:

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}"

Không phải là hiệu quả nhất, nhưng với các tệp nhỏ hơn hoạt động rất sạch sẽ.


2

Nếu các biến đang được tạo và không được lưu vào một tệp, bạn không thể đưa chúng vào source. Cách đơn giản để làm điều đó là:

some command | xargs

-1

Tập lệnh chứa các biến có thể được thực thi được nhập bằng bash. Hãy xem xét script-variable.sh

#!/bin/sh
scr-var=value

Xem xét tập lệnh thực tế nơi biến sẽ được sử dụng:

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

Điều này không hoạt động, nó sẽ chạy tập lệnh Bash trong một quy trình con và sau đó mất bất kỳ môi trường nào (bao gồm các biến) mà nó đã tạo trong suốt vòng đời của nó. Cũng src-varkhông phải là một định danh hợp lệ.
tripleee

-1

Để ngăn xung đột đặt tên, chỉ nhập các biến bạn cần:

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

    echo $(
        source "${file}";
        eval echo \$\{${variable}\}
    )
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.