Berlawanan dengan perintah `sumber`

9

Saya menggunakan sourceperintah dalam skrip bash saya untuk membaca / mencetak nilai variabel

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

Apa kebalikan dari sourceuntuk mengesampingkan variabel?

Hasil yang diharapkan

echo $linuxmachine01

< no output >
yael
sumber
14
Bukan itu sourceyang mengatur variabel di lingkungan Anda, tetapi exportpernyataan dalam file yang Anda source. Jadi kebalikan dari sourceitu bisa source, jika Anda sourcefile yang berbeda yang unsetsemuanya variabel yang sama.
user4556274
2
yael, jangan gunakan ekspor, cukup gunakan name = "val". Ekspor untuk variabel skrip-ke-binari (lingkungan).
ctrl-d
1
Terkait: unix.stackexchange.com/q/382618/117549
Jeff Schaller
2
Ini tidak mungkin. Konsep yang Anda cari disebut Reversible Computing . Bahasa pemrograman harus dirancang secara khusus dengan beberapa batasan ketat agar dapat dibalik. Bash bukan salah satu dari bahasa pemrograman itu.
Jörg W Mittag
1
@ Ohel, itu tidak benar (dan Anda jelas tidak pernah menjalankan tes yang Anda minta ctrl-d lakukan); Anda benar-benar tidak perlu exports. Yang exportdilakukan adalah menyalin nilai-nilai ke lingkungan - tetapi mereka hadir sebagai variabel shell apakah mereka juga didefinisikan sebagai variabel lingkungan. Selain itu, mendefinisikan variabel lingkungan yang tidak perlu mempersingkat panjang baris perintah maksimum Anda, karena mereka disimpan dalam ruang per-proses (terbatas!) Yang sama.
Charles Duffy

Jawaban:

21

Menggunakan subkulit (Disarankan)

Jalankan perintah sumber dalam subkulit:

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

Subkulit didefinisikan oleh parens: (...). Setiap variabel shell yang diatur dalam subkulit dilupakan saat subkulit berakhir.

Menggunakan tidak disetel

Ini menghapus variabel apa pun yang diekspor oleh linuxmachines_mount_point.txt:

unset $(awk -F'[ =]+' '/^export/{print $2}' linuxmachines_mount_point.txt)
  • -F'[ =]+' memberitahu awk untuk menggunakan kombinasi spasi dan tanda sama dengan apa pun sebagai pemisah bidang.

  • /^export/{print $2}

    Ini memberitahu awk untuk memilih garis yang dimulai dengan exportdan kemudian mencetak bidang kedua.

  • unset $(...)

    Ini menjalankan perintah di dalam $(...), menangkap stdout-nya, dan menghapus semua variabel yang dinamai oleh outputnya.

John1024
sumber
mengapa tidak menggunakan ini - untuk saya dalam file `awk '{print $ 2}' | awk -F "=" '{print $ 1}' `; jangan setel $ i; selesai? (lebih sederhana untuk tidak disetel)
yael
2
@el Itu menggunakan proses ekstra dan loop ketika tidak diperlukan. Pendapat mungkin berbeda tetapi saya tidak melihatnya sebagai lebih sederhana. Juga dan berpotensi berbahaya, diasumsikan bahwa setiap baris dalam fileadalah pernyataan ekspor.
John1024
8
@yael Juga, membatalkan variabel dan membatalkan efek samping kode lainnya persis untuk subkulit. Mereka melakukannya dengan sederhana dan andal. Kecuali jika ada alasan khusus sebaliknya, subkulit adalah apa yang seharusnya Anda gunakan.
John1024
4

Anda tidak dapat membuka sourceskrip.

Apa yang dapat Anda lakukan adalah menyimpan semua variabel yang diekspor dalam file sementara, membandingkannya dengan variabel setelah skrip diambil, dan kemudian dihapus dengan unset, misalnya:

export > temp_file
source myscript

#... do some stuff

unset "$(comm -3 <(sort temp_file) <(export | sort) | awk -F'[ =]' '{print $3}' | tr '\n' ' ')"
jimmij
sumber
mengapa tidak menggunakan ini - untuk saya dalam file `awk '{print $ 2}' | awk -F "=" '{print $ 1}' `; jangan setel $ i; selesai? (lebih sederhana untuk tidak disetel)
yael
@yael hanya akan berfungsi jika skrip hanya berisi exports.
jimmij
apa yang Anda maksud "export s", file saya termasuk linuxmachine01 = "sdb sdc sdf sdd sde sdg" dan seterusnya, dan ketika saya menggunakan awk loop, set variabelnya tidak disetel tanpa masalah
yael
@yael Saya tidak tahu bagaimana persisnya tampilan file Anda, jadi saya memberikan beberapa jawaban umum, misalnya bagaimana jika skrip berisi komentar di bagian atas yang mengatakan "# Berikut adalah beberapa variabel untuk diekspor dengan mount point.".
jimmij
2

Anda dapat menggunakan unsetperintah untuk "melupakan" variabel.

francois P
sumber
File bisa dengan mesin diff, jadi bagaimana cara mengeset variabel kedua dalam file?
yael
unset variablename akan melupakannya (Anda dapat menemukannya dijelaskan di bash / sh / ksh / zsh man page) demo untuk itu: pastebin.com/MGQyTZEA
francois P
ya tetapi karena variabel bisa berbeda, skrip bash perlu melakukannya dengan membaca variabel dari file dan menghapusnya, itu tidak bisa statis karena variabel tidak diketahui
yael
lalu ambil jalur ekspor Anda (potong) untuk mendaftar variabel dari file yang tidak disetel ekspor linuxmachine06 = "sdb sde sdf sdd" maka Anda mendapatkan linuxmachine06 sebagai nama untuk tidak disetel contoh: pastebin.com/M9eCtLc7 seperti yang Anda lihat perintah unset di sini lakukan tidak tahu nama variabel itu hanya diketahui pada akhir
francois P
ok saya akan menggunakan sintaks ini untuk menghapus - untuk saya di file `awk '{print $ 2}' | awk -F "=" '{print $ 1}' `; jangan setel $ i; selesai
yael
2

Solusi paling sederhana untuk mendapatkan output yang Anda harapkan (tidak ada) adalah mendeklarasikan ulang variabel sebagai kosong:

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

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

Tentu saja variabel masih didefinisikan (dan diekspor), kosong tetapi didefinisikan:

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

Untuk menghapus variabel dari lingkungan dan shell yang berjalan dengan benar, Anda harus menggunakan unset (cara yang disarankan):

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

Cara paling sederhana untuk melakukan ini adalah dengan memodifikasi skrip Anda sehingga ia juga mendefinisikan perintah untuk membatalkan efek skrip:

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'
Lie Ryan
sumber
Mengapa alias bukan fungsi? Perhatikan bahwa alias dinonaktifkan di shell non-aktif secara default, jadi out-of-the-box, ini tidak akan berfungsi dalam skrip.
Charles Duffy
... sebenarnya, ini akan lebih mudah jika kita mendefinisikan hanya satu variabel, dan dengan demikian hanya memiliki satu untuk tidak disetel:, declare -A linuxmachines=( [01]="sdb sdc sdf" [02]="sde sdd sdb" [03]="whatever" )maka itu hanya unset linuxmachinesuntuk mengembalikan.
Charles Duffy
@CharlesDuffy: alias dan fungsi baik untuk tujuan ini. Alasan saya tidak menyarankan memasukkan semuanya ke dalam satu variabel adalah karena mendefinisikan perintah undo jauh lebih umum. Anda dapat menentukan tidak hanya variabel tetapi juga fungsi, alias, pengaturan sistem, pengaturan terminal, dll. Ini memberikan abstraksi yang lebih baik karena Anda tidak perlu peduli dengan konten yang tepat dari perintah undo.
Lie Ryan
Saya percaya poin saya di atas adalah bahwa alias tidak baik untuk tujuan tersebut, jika "tujuan" termasuk penggunaan non-aktif (mis. Doa dari skrip).
Charles Duffy
0

Anda dapat menulis linuxmachines_mount_point.txt Anda seperti ini

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

Ketika Anda membutuhkan variabel Anda

source linuxmachines_mount_point.txt

Saat Anda ingin menghapus variabel

source linuxmachines_mount_point.txt
ctac_
sumber
0

Jika Anda menggunakan sourceperintah untuk mengaktifkan VirtualEnvironment, Anda bisa keluar menggunakan perintah deactivate.

Serigala Elkan
sumber