Nối tiếp biến shell trong bash hoặc zsh


12

Có cách nào để tuần tự hóa một biến shell? Giả sử tôi có một biến $VARvà tôi muốn có thể lưu nó vào một tệp hoặc bất cứ thứ gì, sau đó đọc lại sau để lấy lại giá trị tương tự?

Có một cách di động để làm điều này? (Tôi không nghĩ vậy)

Có cách nào để làm điều đó trong bash hoặc zsh không?


2
Chú ý: phiên bản câu trả lời của tôi mà bạn chấp nhận vào một ngày khác có một vấn đề nghiêm trọng sẽ phá vỡ trong một số tình huống. Tôi đã viết lại nó để bao gồm các bản sửa lỗi (và thêm các tính năng) và bạn thực sự nên đọc lại từ đầu và chuyển mã của bạn để sử dụng phiên bản cố định.
Caleb

^ Một ví dụ khác về quyền công dân của @ Caleb.
mikeerv

Câu trả lời:


14

Cảnh báo: Với bất kỳ giải pháp nào trong số này, bạn cần lưu ý rằng bạn đang tin tưởng tính toàn vẹn của các tệp dữ liệu để đảm bảo an toàn vì chúng sẽ được thực thi dưới dạng mã shell trong tập lệnh của bạn. Bảo vệ chúng là tối quan trọng đối với bảo mật tập lệnh của bạn!

Thực hiện nội tuyến đơn giản để tuần tự hóa một hoặc nhiều biến

Có, trong cả bash và zsh, bạn có thể tuần tự hóa nội dung của một biến theo cách dễ dàng truy xuất bằng cách sử dụng typesetnội dung và -pđối số. Các định dạng đầu ra là như vậy mà bạn có thể chỉ đơn giản sourcelà đầu ra để lấy lại công cụ của bạn.

 # You have variable(s) $FOO and $BAR already with your stuff
 typeset -p FOO BAR > ./serialized_data.sh

Bạn có thể lấy lại nội dung của mình như thế này sau này trong tập lệnh của bạn hoặc trong tập lệnh khác hoàn toàn:

# Load up the serialized data back into the current shell
source serialized_data.sh

Điều này sẽ làm việc cho bash, zsh và ksh bao gồm cả việc truyền dữ liệu giữa các shell khác nhau. Bash sẽ dịch cái này sang declarehàm dựng sẵn của nó trong khi zsh thực hiện điều này với typesetnhưng vì bash có bí danh để nó hoạt động theo cách nào đó để chúng tôi sử dụng typesetở đây để tương thích ksh.

Triển khai tổng quát phức tạp hơn bằng cách sử dụng các hàm

Việc thực hiện ở trên thực sự đơn giản, nhưng nếu bạn gọi nó thường xuyên, bạn có thể muốn cung cấp cho mình một chức năng tiện ích để làm cho nó dễ dàng hơn. Ngoài ra, nếu bạn từng cố gắng bao gồm các chức năng tùy chỉnh bên trên, bạn sẽ gặp phải các vấn đề với phạm vi thay đổi. Phiên bản này sẽ loại bỏ những vấn đề đó.

Lưu ý cho tất cả những điều này, để duy trì khả năng tương thích chéo bash / zsh, chúng tôi sẽ sửa cả hai trường hợp typesetdeclaredo đó mã phải hoạt động trong một hoặc cả hai shell. Điều này thêm một số lượng lớn và lộn xộn có thể được loại bỏ nếu bạn chỉ làm điều này cho vỏ này hay vỏ khác.

Vấn đề chính với việc sử dụng các hàm cho điều này (hoặc bao gồm mã trong các hàm khác) là typesethàm tạo mã, khi được lấy lại thành tập lệnh từ bên trong hàm, mặc định tạo một biến cục bộ thay vì toàn cục.

Điều này có thể được sửa chữa với một trong một số hack. Nỗ lực ban đầu của tôi để khắc phục điều này là phân tích đầu ra của quá trình tuần tự hóa sedđể thêm -gcờ để mã được tạo xác định một biến toàn cục khi có nguồn gốc trở lại.

serialize() {
    typeset -p "$1" | sed -E '0,/^(typeset|declare)/{s/ / -g /}' > "./serialized_$1.sh"
}
deserialize() {
    source "./serialized_$1.sh"
}

Lưu ý rằng sedbiểu thức sôi nổi là chỉ khớp với lần xuất hiện đầu tiên của 'kiểu chữ' hoặc 'khai báo' và thêm -glàm đối số đầu tiên. Điều cần thiết là chỉ khớp với lần xuất hiện đầu tiên bởi vì, như Stéphane Chazelas đã chỉ ra một cách đúng đắn trong các bình luận, nếu không, nó cũng sẽ khớp với các trường hợp trong đó chuỗi nối tiếp chứa các dòng chữ mới theo sau là từ khai báo hoặc sắp chữ.

Ngoài việc sửa lỗi giả lập phân tích cú pháp ban đầu của tôi , Stéphane cũng đề xuất một cách dễ dàng hơn để hack điều này, không chỉ bên cạnh các vấn đề với phân tích chuỗi mà còn có thể là một móc nối hữu ích để thêm chức năng bổ sung bằng cách sử dụng chức năng trình bao bọc để xác định lại các hành động được thực hiện khi tìm nguồn dữ liệu trở lại. Điều này giả sử bạn không chơi bất kỳ trò chơi nào khác bằng lệnh khai báo hoặc sắp chữ, nhưng kỹ thuật này sẽ dễ thực hiện hơn trong trường hợp bạn đưa chức năng này vào một chức năng khác của chính mình hoặc bạn không kiểm soát được dữ liệu được ghi và có -gthêm cờ hay không . Một cái gì đó tương tự cũng có thể được thực hiện với các bí danh, xem câu trả lời của Gilles để thực hiện.

Để làm cho kết quả thậm chí hữu ích hơn, chúng ta có thể lặp qua nhiều biến được truyền cho các hàm của mình bằng cách giả sử rằng mỗi từ trong mảng đối số là một tên biến. Kết quả trở thành một cái gì đó như thế này:

serialize() {
    for var in $@; do
        typeset -p "$var" > "./serialized_$var.sh"
    done
}

deserialize() {
    declare() { builtin declare -g "$@"; }
    typeset() { builtin typeset -g "$@"; }
    for var in $@; do
        source "./serialized_$var.sh"
    done
    unset -f declare typeset
}

Với một trong hai giải pháp, việc sử dụng sẽ như thế này:

# Load some test data into variables
FOO=(an array or something)
BAR=$(uptime)

# Save it out to our serialized data files
serialize FOO BAR

# For testing purposes unset the variables to we know if it worked
unset FOO BAR

# Load  the data back in from out data files
deserialize FOO BAR

echo "FOO: $FOO\nBAR: $BAR"

declarebashtương đương với ksh's typeset. bash, zshcũng hỗ trợ typesetvì vậy trong vấn đề đó, typesetlà di động hơn. export -plà POSIX, nhưng nó không có bất kỳ đối số nào và đầu ra của nó phụ thuộc vào vỏ (mặc dù nó được chỉ định rõ cho các vỏ POSIX, vì vậy, ví dụ khi bash hoặc ksh được gọi là sh). Hãy nhớ trích dẫn các biến của bạn; sử dụng toán tử split + global ở đây không có nghĩa gì.
Stéphane Chazelas

Lưu ý rằng -Echỉ được tìm thấy trong một số BSD sed. Các giá trị biến có thể chứa các ký tự dòng mới, do đó, sed 's/^.../.../'không được đảm bảo hoạt động chính xác.
Stéphane Chazelas

Điều này thật đúng với gì mà tôi đã tìm kiếm! Tôi muốn một cách thuận tiện để đẩy các biến qua lại giữa các shell.
fwenom

Ý tôi là: a=$'foo\ndeclare bar' bash -c 'declare -p a'để cài đặt sẽ xuất ra một dòng bắt đầu bằng declare. Có lẽ nên làm declare() { builtin declare -g "$@"; }trước khi gọi source(và không đặt sau đó)
Stéphane Chazelas

2
@Gilles, bí danh sẽ không hoạt động bên trong các hàm (cần được xác định tại thời điểm định nghĩa hàm) và với bash có nghĩa là bạn cần thực hiện shopt -s expandaliaskhi không tương tác. Với các hàm, bạn cũng có thể tăng cường declaretrình bao bọc để nó chỉ khôi phục các biến bạn chỉ định.
Stéphane Chazelas

3

Sử dụng chuyển hướng, thay thế lệnh và mở rộng tham số. Dấu ngoặc kép là cần thiết để bảo tồn khoảng trắng và ký tự đặc biệt. Các trailing xlưu các dòng mới trailing sẽ được loại bỏ trong thay thế lệnh.

#!/bin/bash
echo "$var"x > file
unset var
var="$(< file)"
var=${var%x}

Anh ta có lẽ muốn lưu tên biến vào tập tin.
dùng80551

2

Nối tiếp tất cả - POSIX

Trong bất kỳ shell POSIX nào, bạn có thể tuần tự hóa tất cả các biến môi trường với export -p. Điều này không bao gồm các biến shell không xuất. Đầu ra được trích dẫn chính xác để bạn có thể đọc lại trong cùng một vỏ và nhận chính xác các giá trị biến tương tự. Đầu ra có thể không đọc được trong shell khác, ví dụ ksh sử dụng $'…'cú pháp không phải POSIX .

save_environment () {
  export -p >my_environment
}
restore_environment () {
  . ./my_environment
}

Nối tiếp một số hoặc tất cả - ksh, bash, zsh

Ksh (cả pdksh / mksh và ATT ksh), bash và zsh cung cấp một cơ sở tốt hơn với typesetdựng sẵn. typeset -pin ra tất cả các biến được xác định và các giá trị của chúng (zsh bỏ qua các giá trị của các biến đã được ẩn đi typeset -H). Đầu ra chứa khai báo thích hợp để các biến môi trường được xuất khi đọc lại (nhưng nếu một biến đã được xuất khi đọc lại, nó sẽ không được báo cáo), do đó, các mảng được đọc lại dưới dạng mảng, v.v. được trích dẫn chính xác nhưng chỉ được đảm bảo có thể đọc được trong cùng một vỏ. Bạn có thể truyền một tập hợp các biến để tuần tự hóa trên dòng lệnh; nếu bạn không vượt qua bất kỳ biến nào thì tất cả được nối tiếp.

save_some_variables () {
  typeset -p VAR OTHER_VAR >some_vars
}

Trong bash và zsh, việc khôi phục không thể được thực hiện từ một hàm vì các typesetcâu lệnh bên trong hàm nằm trong phạm vi của hàm đó. Bạn cần chạy . ./some_varstrong ngữ cảnh mà bạn muốn sử dụng các giá trị của biến, chú ý rằng các biến đó là toàn cục khi xuất sẽ được phân phối lại thành toàn cục. Nếu bạn muốn đọc lại các giá trị trong một hàm và xuất chúng, bạn có thể khai báo một bí danh hoặc hàm tạm thời. Trong zsh:

restore_and_make_all_global () {
  alias typeset='typeset -g'
  . ./some_vars
  unalias typeset
}

Trong bash (sử dụng declarechứ không phải typeset):

restore_and_make_all_global () {
  alias declare='declare -g'
  shopt -s expand_aliases
  . ./some_vars
  unalias declare
}

Trong ksh, typesetkhai báo các biến cục bộ trong các hàm được xác định bằng function function_name { … }và các biến toàn cục trong các hàm được xác định bằng function_name () { … }.

Nối tiếp một số - POSIX

Nếu bạn muốn kiểm soát nhiều hơn, bạn có thể xuất nội dung của biến theo cách thủ công. Để in chính xác nội dung của một biến vào một tệp, hãy sử dụng printfnội dung dựng sẵn ( echocó một vài trường hợp đặc biệt như echo -ntrên một số vỏ và thêm một dòng mới):

printf %s "$VAR" >VAR.content

Bạn có thể đọc lại điều này $(cat VAR.content), ngoại trừ việc thay thế lệnh sẽ loại bỏ các dòng mới. Để tránh nếp nhăn này, sắp xếp để đầu ra không kết thúc với một dòng mới bao giờ.

VAR=$(cat VAR.content && echo a)
if [ $? -ne 0 ]; then echo 1>&2 "Error reading back VAR"; exit 2; fi
VAR=${VAR%?}

Nếu bạn muốn in nhiều biến, bạn có thể trích dẫn chúng bằng dấu ngoặc đơn và thay thế tất cả dấu ngoặc đơn được nhúng bằng '\''. Hình thức trích dẫn này có thể được đọc lại vào bất kỳ trình bao kiểu Bourne / POSIX nào. Đoạn mã sau hoạt động trong mọi vỏ POSIX. Nó chỉ hoạt động cho các biến chuỗi (và biến số trong shell có chúng, mặc dù chúng sẽ được đọc lại dưới dạng chuỗi), nhưng nó không cố gắng xử lý các biến mảng trong shell có chúng.

serialize_variables () {
  for __serialize_variables_x do
    eval "printf $__serialize_variables_x=\\'%s\\'\\\\n \"\$${__serialize_variables_x}\"" |
    sed -e "s/'/'\\\\''/g" -e '1 s/=.../=/' -e '$ s/...$//'
  done
}

Đây là một cách tiếp cận khác không phân nhánh một quy trình con nhưng nặng hơn về thao tác chuỗi.

serialize_variables () {
  for __serialize_variables_var do
    eval "__serialize_variables_tail=\${$__serialize_variables_var}"
    while __serialize_variables_quoted="$__serialize_variables_quoted${__serialize_variables_tail%%\'*}"
          [ "${__serialize_variables_tail%%\'*}" != "$__serialize_variables_tail" ]; do
      __serialize_variables_tail="${__serialize_variables_tail#*\'}"
      __serialize_variables_quoted="${__serialize_variables_quoted}'\\''"
    done
    printf "$__serialize_variables_var='%s'\n" "$__serialize_variables_quoted"
  done
}

Lưu ý rằng trên các shell cho phép các biến chỉ đọc, bạn sẽ gặp lỗi nếu bạn cố đọc lại một biến chỉ đọc.


Điều này mang lại các biến như $PWD$_- vui lòng xem bình luận của riêng bạn bên dưới.
mikeerv

@Caleb Làm thế nào về việc tạo typesetmột bí danh cho typeset -g?
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Tôi đã nghĩ đến điều đó sau khi Stephanie đề xuất phương thức hàm, nhưng tôi không chắc chắn làm thế nào để thiết lập một cách hợp lý các tùy chọn mở rộng bí danh cần thiết trên các shell. Có lẽ bạn có thể đặt nó trong câu trả lời của bạn như là một thay thế khả thi cho chức năng mà tôi đưa vào.
Caleb

0

Rất cảm ơn @ stéphane-chazelas, người đã chỉ ra tất cả các vấn đề với những nỗ lực trước đây của tôi, giờ đây nó dường như hoạt động để nối tiếp một mảng thành thiết bị xuất chuẩn hoặc thành một biến.

Kỹ thuật này không phân tích cú pháp đầu vào (không giống như declare -a/ declare -p) và do đó an toàn trước việc chèn các ký tự đại diện độc hại vào văn bản được xê -ri hóa.

Lưu ý: dòng mới không được thoát, vì readxóa \<newlines>cặp ký tự, -d ...thay vào đó phải được chuyển qua để đọc, và sau đó dòng mới không thoát được giữ nguyên.

Tất cả điều này được quản lý trong unserialisechức năng.

Hai ký tự ma thuật được sử dụng, dấu tách trường và dấu tách bản ghi (để nhiều mảng có thể được nối tiếp vào cùng một luồng).

Các ký tự này có thể được định nghĩa là FSRSnhưng không thể được định nghĩa là newlineký tự vì một dòng mới thoát được xóa bởi read.

Ký tự thoát phải là \dấu gạch chéo ngược, vì đó là những gì được sử dụng readđể tránh ký tự được nhận dạng là một IFSký tự.

serialisesẽ nối tiếp "$@"với thiết bị xuất chuẩn, serialise_tosẽ nối tiếp với biến có tên trong$1

serialise() {
  set -- "${@//\\/\\\\}" # \
  set -- "${@//${FS:-;}/\\${FS:-;}}" # ; - our field separator
  set -- "${@//${RS:-:}/\\${RS:-:}}" # ; - our record separator
  local IFS="${FS:-;}"
  printf ${SERIALIZE_TARGET:+-v"$SERIALIZE_TARGET"} "%s" "$*${RS:-:}"
}
serialise_to() {
  SERIALIZE_TARGET="$1" serialise "${@:2}"
}
unserialise() {
  local IFS="${FS:-;}"
  if test -n "$2"
  then read -d "${RS:-:}" -a "$1" <<<"${*:2}"
  else read -d "${RS:-:}" -a "$1"
  fi
}

và unerialise với:

unserialise data # read from stdin

hoặc là

unserialise data "$serialised_data" # from args

ví dụ

$ serialise "Now is the time" "For all good men" "To drink \$drink" "At the \`party\`" $'Party\tParty\tParty'
Now is the time;For all good men;To drink $drink;At the `party`;Party   Party   Party:

(không có dòng mới)

đọc lại:

$ serialise_to s "Now is the time" "For all good men" "To drink \$drink" "At the \`party\`" $'Party\tParty\tParty'
$ unserialise array "$s"
$ echo "${array[@]/#/$'\n'}"

Now is the time 
For all good men 
To drink $drink 
At the `party` 
Party   Party   Party

hoặc là

unserialise array # read from stdin

Bash readtôn trọng ký tự thoát \(trừ khi bạn truyền cờ -r) để loại bỏ ý nghĩa đặc biệt của các ký tự, chẳng hạn như phân tách trường đầu vào hoặc phân cách dòng.

Nếu bạn muốn tuần tự hóa một mảng thay vì danh sách đối số đơn thuần thì chỉ cần chuyển mảng của bạn làm danh sách đối số:

serialise_array "${my_array[@]}"

Bạn có thể sử dụng unserialisetrong một vòng lặp như bạn muốn readbởi vì nó chỉ là một lần đọc được bao bọc - nhưng hãy nhớ rằng luồng không được phân tách dòng mới:

while unserialise array
do ...
done

Nó không hoạt động nếu các phần tử chứa không thể in (trong ngôn ngữ hiện tại) hoặc các ký tự điều khiển như TAB hoặc dòng mới như sau đó bashzshhiển thị chúng dưới dạng $'\xxx'. Hãy thử với bash -c $'printf "%q\n" "\t"'hoặcbash -c $'printf "%q\n" "\u0378"'
Stéphane Chazelas

tootin chết tiệt, bạn đã đúng! Tôi sẽ sửa đổi câu trả lời của mình để không sử dụng printf% q mà thay vào đó là $ {@ // .. / ..} để thoát khoảng trắng
Sam Liddicott

Giải pháp đó phụ thuộc vào $IFSviệc không được sửa đổi và bây giờ không thể khôi phục các phần tử mảng trống đúng cách. Trên thực tế, sẽ có ý nghĩa hơn khi sử dụng một giá trị khác của IFS và sử dụng -d ''để tránh phải thoát khỏi dòng mới. Ví dụ, sử dụng :làm dấu tách trường và chỉ thoát khỏi dấu gạch chéo ngược đó và sử dụng IFS=: read -ad '' arrayđể nhập.
Stéphane Chazelas

Yup .... Tôi quên mất điều trị đặc biệt sụp đổ không gian trắng khi được sử dụng như một dấu tách trường trong đọc. Tôi rất vui vì bạn đang ở trên bóng ngày hôm nay! Bạn đã đúng về -d "" để tránh thoát \ n, nhưng trong trường hợp của tôi, tôi muốn đọc một dòng nối tiếp - mặc dù vậy tôi sẽ điều chỉnh câu trả lời. Cảm ơn!
Sam Liddicott

Thoát khỏi dòng mới không cho phép nó được bảo tồn, nó làm cho nó biến mất một lần read. backslash-newline cho readlà một cách để tiếp tục một dòng logic vào một dòng vật lý khác. Chỉnh sửa: ah Tôi thấy bạn đề cập đến vấn đề với dòng mới.
Stéphane Chazelas

0

Bạn có thể sử dụng base64:

$ VAR="1/ 
,x"
$ echo "$VAR" | base64 > f
$ VAR=$(cat f | base64 -d)
$ echo "${VAR}X"
1/ 
,xX

-2
printf 'VAR=$(cat <<\'$$VAR$$'\n%s\n'$$VAR$$'\n)' "$VAR" >./VAR.file

Một cách khác để làm điều đó là đảm bảo bạn xử lý tất cả các phần 'cứng như thế này:

sed '"s/'"'/&"&"&/g;H;1h;$!d;g;'"s/.*/VAR='&'/" <<$$VAR$$ >./VAR.file
$VAR
$$VAR$$

Hoặc với export:

env - "VAR=$VAR" sh -c 'export -p' >./VAR.file 

Các tùy chọn thứ nhất và thứ hai hoạt động trong bất kỳ shell POSIX nào, giả sử rằng giá trị của biến không chứa chuỗi:

"\n${CURRENT_SHELLS_PID}VAR${CURRENT_SHELLS_PID}\n" 

Tùy chọn thứ ba sẽ hoạt động cho mọi shell POSIX nhưng có thể cố gắng xác định các biến khác như _hoặc PWD. Mặc dù vậy, sự thật là các biến duy nhất mà nó có thể cố gắng xác định được đặt và duy trì bởi chính shell - và vì vậy ngay cả khi bạn nhập exportgiá trị cho bất kỳ một trong số chúng - $PWDví dụ: shell sẽ chỉ đặt lại chúng thành giá trị chính xác ngay lập tức dù sao đi nữa - hãy thử làm PWD=any_valuevà tự mình xem.

Và bởi vì - ít nhất là với GNU bash- đầu ra gỡ lỗi được tự động trích dẫn an toàn để nhập lại vào shell, nên điều này hoạt động bất kể số lượng 'trích dẫn cứng trong "$VAR":

 PS4= VAR=$VAR sh -cx 'VAR=$VAR' 2>./VAR.file

$VAR sau này có thể được đặt thành giá trị đã lưu trong bất kỳ tập lệnh nào trong đó đường dẫn sau hợp lệ với:

. ./VAR.file

Tôi không chắc những gì bạn đã cố gắng viết trong lệnh đầu tiên. $$Là PID của shell đang chạy, bạn có nhận được trích dẫn sai và có nghĩa \$hay gì không? Cách tiếp cận cơ bản của việc sử dụng tài liệu ở đây có thể được thực hiện để hoạt động, nhưng nó khó, không phải là vật liệu một lớp: bất cứ điều gì bạn chọn làm điểm đánh dấu cuối, bạn phải chọn thứ gì đó không xuất hiện trong chuỗi.
Gilles 'SO- ngừng trở nên xấu xa'

Lệnh thứ hai không hoạt động khi $VARchứa %. Lệnh thứ ba không phải lúc nào cũng hoạt động với các giá trị chứa nhiều dòng (ngay cả sau khi thêm dấu ngoặc kép rõ ràng bị thiếu).
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles - Tôi biết pid của nó - Tôi đã sử dụng nó như một nguồn đơn giản để thiết lập một dấu phân cách duy nhất. Bạn có ý nghĩa gì bởi "không phải lúc nào" chính xác? Và tôi không hiểu những gì trích dẫn kép bị thiếu - tất cả chúng là các bài tập biến. Dấu ngoặc kép chỉ gây nhầm lẫn tình hình trong bối cảnh đó.
mikeerv

@Gilles - Tôi rút lại điều chuyển nhượng - đó là một đối số env. Tôi vẫn tò mò ý của bạn về nhiều dòng - sedxóa mọi dòng cho đến khi gặp VAR=đến dòng cuối cùng - vì vậy tất cả các dòng $VARđược truyền lại. Bạn có thể vui lòng cung cấp một ví dụ phá vỡ nó?
mikeerv

Ah, xin lỗi, phương pháp thứ ba không hoạt động (với phần trích dẫn trích dẫn). Vâng, giả sử tên biến (ở đây VAR) là không thay đổi PWDhoặc _hoặc có lẽ những người khác rằng một số vỏ xác định. Phương pháp thứ hai yêu cầu bash; định dạng đầu ra từ -vkhông được chuẩn hóa (không có công việc dash, ksh93, mksh và zsh).
Gilles 'SO- ngừng trở nên xấu xa'

-2

Gần giống nhau nhưng hơi khác một chút:

Từ kịch bản của bạn:

#!/usr/bin/ksh 

save_var()
{

    (for ITEM in $*
    do
        LVALUE='${'${ITEM}'}'
        eval RVALUE="$LVALUE"
        echo "$ITEM=\"$RVALUE\""  
    done) >> $cfg_file
}

restore_vars()
{
    . $cfg_file
}

cfg_file=config_file
MY_VAR1="Test value 1"
MY_VAR2="Test 
value 2"

save_var MY_VAR1 MY_VAR2
MY_VAR1=""
MY_VAR2=""

restore_vars 

echo "$MY_VAR1"
echo "$MY_VAR2"

Lần này ở trên được thử nghiệm.


Tôi có thể thấy bạn đã không kiểm tra! Logic cốt lõi hoạt động, nhưng đó không phải là một chút khó khăn. Một chút khó khăn là trích dẫn mọi thứ một cách chính xác, và bạn không làm gì trong số đó. Hãy thử các biến có giá trị chứa newlines, ', *vv
Gilles 'Somali dừng vốn là xấu'

echo "$LVALUE=\"$RVALUE\""được cho là cũng giữ các dòng mới và kết quả trong cfg_file sẽ giống như: MY_VAR1 = "Line1 \ nLine 2" Do đó, khi eval MY_VAR1 cũng sẽ chứa các dòng mới. Tất nhiên bạn có thể gặp vấn đề nếu giá trị được lưu trữ của bạn chứa chính "char. Nhưng điều đó có thể được chăm sóc là tốt.
vadimbog

1
Btw, tại sao phải bỏ phiếu một cái gì đó đang trả lời chính xác câu hỏi được hỏi ở đây? Ở trên hoạt động rất tốt cho tôi và sử dụng ở mọi nơi trong các kịch bản của tôi?
vadimbog
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.