Tidak berhasil sumber .bashrc dari skrip shell

51

Biasanya kita dapat mencari ~/.bashrcfile menggunakan perintah ini

source ~/.bashrc

tetapi jika saya menulis ini dalam skrip shell dan menjalankannya, tidak ada yang terjadi. Mengapa?
Apakah ada cara untuk melakukan ini?

Skrip saya:

#!/bin/bash
chmod a+x ~/.bashrc
source ~/.bashrc

Juga mencoba .(titik) alih-alih source. Hasil yang sama

shantanu
sumber

Jawaban:

26

Script shell dijalankan dalam instance shell-nya sendiri. Semua pengaturan variabel, definisi fungsi dan semacamnya hanya memengaruhi instance ini (dan mungkin anak-anaknya) tetapi tidak pada shell panggilan sehingga tidak digunakan setelah skrip selesai.

Sebaliknya, sourceperintah tidak memulai turunan shell baru tetapi menggunakan shell saat ini sehingga perubahan tetap ada.

Jika Anda ingin pintasan untuk membaca .bashrc Anda gunakan fungsi shell atau alias, bukan skrip shell, seperti

alias brc='source ~/.bashrc'
Florian Diesch
sumber
Terima kasih atas balasan cepat Anda. Solusi Anda mungkin berfungsi tetapi saya harus mengedit file bashrc secara manual untuk menyimpan baris 'aliac brc = ....'. Saya mencoba mengembangkan gui untuk mengubah variabel lingkungan. Jadi saya tidak bisa mengedit file bashrc komputer lain secara manual.
shantanu
1
Anda harus menjalankan source ~/.bashrcshell yang ingin Anda ubah lingkungannya. Anda tidak dapat mengubahnya dari proses lain. Mungkin (secara global) menambahkan alias ini bisa menjadi bagian dari proses pemasangan GUI Anda.
Florian Diesch
1
jadi apakah saya meletakkan perintah alias Anda sebelumnya dalam skrip dan kemudian memanggil brc ketika saya ingin sumber .bashrc saya atau saya perlu menempatkan perintah alias itu di file di suatu tempat?
user137717
Apa yang akhirnya saya lakukan adalah perpanjangan dari jawaban Florian Diesch. Anda bisa menggunakan alias multi-line: alias brc = 'chmod a + x ~ / .bashrc; source ~ / .bashrc 'Saya masih sangat baru, jadi saya tidak yakin apakah ini dianggap' praktik buruk '. Tapi itu berhasil.
A_user_appears
13

.bashrcBiasanya Anda mulai:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

Karena skrip Anda tidak memiliki set PS1 (karena itu tidak interaktif), skrip tidak me-reset path karena keluar lebih awal. Untuk menunjukkan, modifikasi skrip Anda:

    #!/bin/bash
    chmod a+x ~/.bashrc
    PS1='$ '
    source ~/.bashrc

ini sekarang akan memungkinkan skrip Anda untuk bekerja dengan yang baru .bashrc. Catatan: setelah skrip Anda keluar, env akan diatur sesuai dengan sebelum memulai skrip. Perubahan akan tercermin pada saat terminal dimulai berikutnya.

ravi nankani
sumber
Paling tidak sejak 16,04 dan mungkin sebelumnya, Ubuntu default .bashrcmenggunakan cara yang lebih andal untuk memeriksa apakah shell itu interaktif. /etc/bash.bashrcmasih memiliki tes PS1.
Zanna
12

Mencoba:

exec bash

Ini harus memuat ulang ~ / .bashrc, ~ / .bash_aliases, dll.

Alin Andrei
sumber
9
Ini menggantikan proses bash saat ini dengan yang baru. Ini tidak jauh lebih pendek atau lebih mudah daripada menggunakan sourcetetapi menghancurkan variabel apa pun dan sedemikian rupa sehingga pengguna telah mengatur secara manual - yang mungkin atau mungkin tidak apa yang Anda inginkan.
Florian Diesch
tunggu, dalam konteks skrip Shell dengan perintah lain setelah bashrc sourcing, apakah Anda menempatkan perintah yang memerlukan status bash baru setelah itu exec bash, cara saya memahaminya setelah akan tetap dalam pengaturan bash yang sama seperti sebelumnya?
tatsu
11

Saya ingin melengkapi jawaban ravi :

Perilaku ini khusus untuk Ubuntu (dan mungkin sebagian besar distro), karena ~/.bashrcfile default Anda dimulai dengan korsleting, Ubuntu 18.04, misalnya:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

Itu akan menghentikan evaluasi file jika berjalan di shell non-interaktif, yang merupakan kasus skrip Anda karena semua skrip dijalankan di shell non-interaktif , dan selanjutnya setiap file yang Anda sourcewarisi akan mewarisi properti ini.

eval retas

Saya menemukan peretasan jelek untuk menyelesaikan Ubuntu secara khusus, menggunakan evalbukannya source:

eval "$(cat ~/.bashrc | tail -n +10)"

Itu hanya melompati beberapa baris pertama dan mengevaluasi sisanya ~/.bashrcsehingga sisanya dievaluasi dan memodifikasi eksekusi saat ini.

Ketahuilah bahwa ini adalah angka ajaib dan mungkin tidak berfungsi di seluruh versi Ubuntu; tetapi mungkin solusi yang bagus jika Anda membuat skrip untuk sistem yang lebih atau kurang dikenal.

Solusi yang lebih bagus mungkin melibatkan penggunaan regex untuk menargetkan bit spesifik yang menghentikan evaluasi.

Alternatif Shebang

Alternatif lain yang mungkin bekerja lebih baik dalam beberapa skenario adalah memaksa skrip untuk berjalan di shell interaktif dengan menambahkan bendera di shebang :

#!/bin/bash -i

Waspadai beberapa hal:

  • Ini adalah praktik yang lebih baik untuk menggunakan #!/usr/bin/env bashformulir tetapi dengan cara ini Anda tidak dapat memulai shell dengan argumen .
  • Dengan menggunakan -irangkaian konsekuensinya sendiri, di antaranya, program akan meminta interaksi pengguna dan ini biasanya tidak dimaksudkan untuk skrip, misalnya, menginstal debpaket mungkin menghentikan skrip saat dpkg configurediminta .
  • Awalnya saya mencoba menggunakan set -idan set +imematikan fitur di tempat saya membutuhkannya, tetapi ini tidak berhasil .
stefanmaric
sumber
2

Tidak ada metode lain yang bekerja untuk saya [ source /path/to/filevs . ./path/to/file, alias, dll ...], sampai, terima kasih untuk tutorial ini saya menemukan bahwa menggunakan:

#!/usr/bin/env bash peristiwa

alih-alih yang lebih sederhana, #!/usr/bin/envargumen dapat diteruskan ke juru bahasa, yang menurut saya kuncinya di sini - lihat dokumen ini untuk info lebih lanjut.

Bagaimanapun, jika perintah sumber dalam bentuk apa pun tidak berfungsi untuk Anda, coba periksa shebang Anda, itu mungkin masalahnya :)

Nikksno
sumber