Đối diện với lệnh `source`


9

Tôi sử dụng sourcelệnh trong tập lệnh bash của mình để đọc / in các giá trị biến

more linuxmachines_mount_point.txt

export linuxmachine01="sdb sdc sdf sdd sde sdg"
export linuxmachine02="sde sdd sdb sdf sdc"
export linuxmachine03="sdb sdd sdc sde sdf"
export linuxmachine06="sdb sde sdf sdd"

source  linuxmachines_mount_point.txt

echo $linuxmachine01
sdb sdc sdf sdd sde sdg

Điều ngược lại sourceđể bỏ đặt các biến là gì?

Kết quả mong đợi

echo $linuxmachine01

< no output >

14
Không phải sourcelà thiết lập các biến trong môi trường của bạn, mà là các exportcâu lệnh trong tệp mà bạn source. Vì vậy, điều ngược lại sourcecó thể là source, nếu bạn sourcelà một tệp khác có unsettất cả các biến giống nhau.
user4556274

2
yael, không sử dụng xuất khẩu, chỉ sử dụng tên = "val". Xuất khẩu là cho các biến script-to-nhị phân (môi trường).
ctrl-d


2
Điều này là không thể. Khái niệm bạn đang tìm kiếm được gọi là Máy tính đảo ngược . Ngôn ngữ lập trình cần phải được thiết kế đặc biệt với một số hạn chế nghiêm trọng để có thể đảo ngược. Bash không phải là một trong những ngôn ngữ lập trình.
Jörg W Mittag

1
@yael, điều đó không đúng sự thật (và rõ ràng là bạn chưa bao giờ chạy thử nghiệm mà bạn đang nói với ctrl-d để làm); bạn hoàn toàn không cần exports. Tất cả exportđều là sao chép các giá trị vào môi trường - nhưng chúng hiện diện dưới dạng các biến shell cho dù chúng có được xác định là biến môi trường hay không. Hơn nữa, việc xác định các biến môi trường không cần thiết sẽ rút ngắn độ dài dòng lệnh tối đa của bạn, vì chúng được lưu trữ trong cùng một không gian (giới hạn!).
Charles Duffy

Câu trả lời:


21

Sử dụng một lớp con (Được khuyến nghị)

Chạy lệnh nguồn trong một khung con:

(
source linuxmachines_mount_point.txt
cmd1 $linuxmachine02
other_commands_using_variables
etc
)
echo $linuxmachine01  # Will return nothing

Subshells được xác định bởi parens : (...). Bất kỳ biến shell nào được đặt trong lớp con đều bị quên khi lớp con kết thúc.

Sử dụng unset

Điều này bỏ đặt bất kỳ biến nào được xuất bởi linuxmachines_mount_point.txt:

unset $(awk -F'[ =]+' '/^export/{print $2}' linuxmachines_mount_point.txt)
  • -F'[ =]+' yêu cầu awk sử dụng bất kỳ sự kết hợp nào của không gian và các dấu bằng như dấu phân cách trường.

  • /^export/{print $2}

    Điều này cho awk chọn các dòng bắt đầu exportvà sau đó in trường thứ hai.

  • unset $(...)

    Điều này chạy lệnh bên trong $(...), nắm bắt thiết bị xuất chuẩn của nó và bỏ đặt bất kỳ biến nào được đặt tên theo đầu ra của nó.


tại sao không sử dụng cái này - cho tôi trong tập tin `awk '{print $ 2}' | awk -F "=" '{in $ 1}' `; bỏ đặt $ i; làm xong ? (đơn giản hơn cho unset)
yael 30/12/17

2
@yael Điều đó sử dụng một quá trình bổ sung và một vòng lặp khi không cần thiết. Ý kiến ​​có thể khác nhau nhưng tôi không thấy điều đó đơn giản hơn. Ngoài ra và có khả năng nguy hiểm, nó giả định rằng mỗi dòng trong filelà một báo cáo xuất khẩu.
John1024

8
@yael Ngoài ra, bỏ đặt các biến và hoàn tác các tác dụng phụ của mã khác chính xác là những gì các lớp con dành cho. Họ làm điều đó một cách đơn giản và đáng tin cậy. Trừ khi có một số lý do đặc biệt khác, subshells là những gì bạn nên sử dụng.
John1024

4

Bạn không thể bỏ sourcetập lệnh.

Những gì bạn có thể làm là lưu trữ tất cả các biến đã xuất trong một tệp tạm thời, so sánh nó với các biến sau khi tập lệnh có nguồn gốc, và sau đó loại bỏ tràn unset, ví dụ:

export > temp_file
source myscript

#... do some stuff

unset "$(comm -3 <(sort temp_file) <(export | sort) | awk -F'[ =]' '{print $3}' | tr '\n' ' ')"

tại sao không sử dụng cái này - cho tôi trong tập tin `awk '{print $ 2}' | awk -F "=" '{in $ 1}' `; bỏ đặt $ i; làm xong ? (đơn giản hơn cho unset)
yael 30/12/17

@yael nó sẽ chỉ hoạt động nếu tập lệnh chỉ chứa exports.
jimmij

những gì bạn có nghĩa là "xuất khẩu s", tập tin của tôi bao gồm linuxmachine01 = "sdb sdc sdf sdd SDE SDG" và như vậy, và khi tôi sử dụng vòng lặp awk unset biến của nó không có vấn đề
Yael

@yael Tôi không biết chính xác tệp của bạn trông như thế nào, vì vậy tôi đã đưa ra một số câu trả lời chung chung, ví dụ như nếu tập lệnh chứa một nhận xét ở trên cùng có nội dung "# Đây là một số biến để xuất với điểm gắn kết."
jimmij

2

Bạn có thể sử dụng unsetlệnh để "quên" các biến.


tập tin có thể là với máy diff, vậy làm thế nào để bỏ đặt các biến thứ hai trong tập tin?
yael

unset matrixblename sẽ quên nó (bạn có thể tìm thấy nó được giải thích trong trang bash / sh / ksh / zsh) của nó: pastebin.com/MGQyTZEA
francois P

có nhưng vì các biến có thể là khác nhau, tập lệnh bash cần thực hiện bằng cách đọc biến từ tệp và bỏ đặt chúng, không thể tĩnh vì biến không xác định
yael 30/12/17

sau đó grep các dòng xuất của bạn (cắt) để liệt kê các biến từ tệp để hủy đặt linuxmachine06 = "sdb sde sdf sdd", sau đó bạn lấy linuxmachine06 làm tên để bỏ đặt ví dụ: pastebin.com/M9eCtLc7 khi bạn thấy lệnh unset ở đây 'không biết tên biến nó chỉ được biết đến ở cuối
francois P

ok Tôi sẽ sử dụng cú pháp này để bỏ đặt - cho tôi trong tệp `awk '{print $ 2}' | awk -F "=" '{in $ 1}' `; bỏ đặt $ i; xong
yael

2

Giải pháp đơn giản nhất để có đầu ra mà bạn mong đợi (không có gì) là khai báo lại biến là trống:

$ export linuxmachine01="sdb sdc sdf sdd sde sdg"
$ echo "$linuxmachine01"
sdb sdc sdf sdd sde sdg

$ linuxmachine01=""
$ echo "$linuxmachine01"
$

Tất nhiên biến vẫn được xác định (và xuất), trống nhưng được xác định:

$ declare -p linuxmachine01
declare -x linuxmachine01=""

Để loại bỏ chính xác biến khỏi cả môi trường và vỏ đang chạy, bạn nên sử dụng unset (cách được khuyến nghị):

$ unset linuxmachine01
$ declare -p linuxmachine01
bash: declare: linuxmachine01: not found
$ echo "$linuxmachine01"
$

1

Cách đơn giản nhất để làm điều này là sửa đổi tập lệnh của bạn để nó cũng xác định một lệnh để hoàn tác hiệu ứng của tập lệnh:

export linuxmachine01="sdb sdc sdf sdd sde sdg"
export linuxmachine02="sde sdd sdb sdf sdc"
export linuxmachine03="sdb sdd sdc sde sdf"
export linuxmachine06="sdb sde sdf sdd"
alias linuxmachines_mount_point='for v in linuxmachine01 linuxmachine02 linuxmachine03 linuxmachine04; do unset $v; done; unalias linuxmachines_mount_point'

Tại sao một bí danh chứ không phải là một chức năng? Lưu ý rằng các bí danh bị tắt trong các vỏ không tương tác theo mặc định, do đó, ngoài luồng, điều này sẽ không hoạt động trong một tập lệnh.
Charles Duffy

... thực ra, điều này sẽ còn dễ dàng hơn nữa nếu chúng ta chỉ xác định một biến và do đó chỉ có một biến để bỏ đặt: declare -A linuxmachines=( [01]="sdb sdc sdf" [02]="sde sdd sdb" [03]="whatever" )đó là chỉ unset linuxmachinesđể hoàn nguyên.
Charles Duffy

@CharlesDuffy: cả bí danh và chức năng đều ổn cho mục đích này. Lý do tôi không khuyên bạn nên đặt mọi thứ vào một biến là việc xác định lệnh hoàn tác sẽ chung chung hơn nhiều. Bạn có thể xác định không chỉ các biến mà cả các hàm, bí danh, cài đặt hệ thống, cài đặt đầu cuối, v.v. Nó cung cấp một sự trừu tượng hóa tốt hơn vì bạn không phải quan tâm đến nội dung chính xác của lệnh hoàn tác.
Lie Ryan

Tôi tin rằng quan điểm của tôi ở trên là các bí danh không tốt cho mục đích, nếu "mục đích" bao gồm việc sử dụng không tương tác (ví dụ: lời gọi từ các tập lệnh).
Charles Duffy

0

Bạn có thể viết linuxmachines_mount_point.txt của bạn như thế này

test "$linuxmachine01" && unset -v linuxmachine01 || linuxmachine01="sdb sdc sdf sdd sde sdg"

Khi bạn cần các biến của bạn

source linuxmachines_mount_point.txt

Khi bạn muốn loại bỏ các biến

source linuxmachines_mount_point.txt

0

Nếu bạn đang sử dụng sourcelệnh để kích hoạt a VirtualEnvironment, bạn có thể thoát lệnh bằng lệnh deactivate.

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.