V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lancegin
V2EX  ›  程序员

shell 设置环境变量的问题

  •  
  •   lancegin ·
    lancegin · 2017-03-24 12:57:01 +08:00 · 7033 次点击
    这是一个创建于 2589 天前的主题,其中的信息可能已经有所发展或是发生改变。

    遇到一个不能理解的问题

    在 shell 脚本中设置环境变量,执行脚本之后环境变量未生效,但在 terminal 手动 source 一下 bashrc 之后就生效了
    

    部分 shell 脚本如下:

    #!/bin/bash
    .
    .
    .
    DS_KEYFROM="xxx"
    DS_KEY="xxx"
    echo "export DS_KEYFROM=\"$DS_KEYFROM\"" >> ~/.bashrc
    echo "export DS_KEY=\"$DS_KEY\"" >> ~/.bashrc
    source ~/.bashrc
    .
    .
    .
    

    执行脚本之后echo $DS_KEYFROMecho $DS_KEY都没有值

    但是查看 bashrc cat ~/.bashrc是显示已经设置成功的:

    .
    .
    .
    export DS_KEYFROM="xxx"
    export DS_KEY="xxx"
    .
    .
    .
    

    此时如果手动 source 一下 bashrc source ~/.bashrc,环境变量就生效了。

    有人知道怎么解决这个问题吗?如何直接执行脚本之后就让环境变量生效?

    30 条回复    2017-03-26 21:28:30 +08:00
    Dx2619
        1
    Dx2619  
       2017-03-24 13:01:11 +08:00 via iPhone
    因为脚本执行的 shell 进程号和执行完脚步 echo 的进程号不一致呀。
    Dx2619
        2
    Dx2619  
       2017-03-24 13:04:13 +08:00 via iPhone
    @Dx2619 因为脚本执行的 shell 进程号和你在脚本使用过后 echo 时用的 shell 的进程号不一致。你在当前 shell 手工 source 一下或者开一个新的 shell 就可以了
    Dx2619
        3
    Dx2619  
       2017-03-24 13:09:34 +08:00 via iPhone
    简单说是因为当前 shell 未重载 bashrc 导致的。可以试试. ./a.sh
    lancegin
        4
    lancegin  
    OP
       2017-03-24 13:11:26 +08:00
    @Dx2619
    但现在我的需求就是在不手动 source 的前提下直接让环境变量生效,如体直接在 shell 脚本里面的 `source ~/.bashrc`

    ps 重开一个 shell 也是无效的 没有手动 source 的前提下 感觉就是没有设置成功的
    lancegin
        5
    lancegin  
    OP
       2017-03-24 13:15:08 +08:00
    @Dx2619 刚觉像是直接执行脚本的时候 开了一个子 shell ,于是我脚本中的 source 命令相当于在子 shell 中执行了
    imkh
        6
    imkh  
       2017-03-24 13:25:08 +08:00
    用 source script.sh 直接执行脚本 不用 sh script.sh
    greyterry
        7
    greyterry  
       2017-03-24 13:27:38 +08:00
    1 楼正解
    lancegin
        8
    lancegin  
    OP
       2017-03-24 13:34:14 +08:00
    @imkh 如果这是个 install 脚本 有没有办法可以直接通过 raw 执行呢? 还是我必须得把脚本下载到本地之后再手动 source 执行?
    imkh
        9
    imkh  
       2017-03-24 13:36:55 +08:00
    @lancegin 一样的。 source script.sh 就是. ./script.sh ,在当前 shell 内执行、 而不是产生一个 sub-shell 来执行
    skydiver
        10
    skydiver  
       2017-03-24 13:46:12 +08:00
    @lancegin eval $(curl xxxx)
    lancegin
        11
    lancegin  
    OP
       2017-03-24 13:51:58 +08:00
    @imkh 了解 目前确实只有手动 source 才能解决问题了
    thekll
        12
    thekll  
       2017-03-24 15:35:03 +08:00 via iPhone
    感觉你好像并没理解楼上两位的意思。
    https://en.m.wikipedia.org/wiki/Source_(command)
    thekll
        13
    thekll  
       2017-03-24 15:36:39 +08:00 via iPhone
    直接 source 执行你的脚本。
    lancegin
        14
    lancegin  
    OP
       2017-03-24 15:48:50 +08:00
    @thekll 楼上说的都明白 只是没有解决我的问题 。我是希望不通过手动 source 执行就能解决问题,然而貌似并不行。

    具体情况是这样
    假设有一段 install 脚本放在 github 仓库上,那我可以用 `curl -s raw_file.sh | bash` 直接执行,但如果脚本里面有设置环境变量的语句,那就无法实现了
    artandlol
        15
    artandlol  
       2017-03-24 16:00:22 +08:00
    要嘛是写死在
    /etc/rc.local 然后 reboot
    或者写在 /etc/profile 然后 source /etc/profile
    要嘛只能在程序内部调用

    不建议放在 bashrc ,因为定时任务的时候是没有登陆操作,没法加载你这个 bashrc
    lancegin
        16
    lancegin  
    OP
       2017-03-24 16:22:43 +08:00 via iPhone
    @artandlol 就是个在当前用户下作用的小脚本,所以就放 bashrc 了👨🏼‍💻
    julyclyde
        17
    julyclyde  
       2017-03-24 16:28:19 +08:00
    @artandlol rc.local 也不是全局的
    21grams
        18
    21grams  
       2017-03-24 16:29:38 +08:00
    所以你以为 source 是做什么用的
    lancegin
        19
    lancegin  
    OP
       2017-03-24 16:30:38 +08:00
    @21grams 天真的以为在脚本中 source 就足够了
    thekll
        20
    thekll  
       2017-03-24 22:16:28 +08:00 via iPhone
    Bash 有好几种启动方式: login 、 interactive 等,相关的几个配置文件作用也有区别。

    ~/.bashrc 好像对于 Bash 脚本文件是不起作用的。
    你可以试试~/.bash_profile 、~/.profile 。

    具体说明请参考:
    https://en.m.wikipedia.org/wiki/Bash_(Unix_shell)
    zzlyzq
        21
    zzlyzq  
       2017-03-24 23:04:25 +08:00
    子进程无法影响到父进程的环境变量
    zzlyzq
        22
    zzlyzq  
       2017-03-24 23:04:48 +08:00
    父进程可以通过 export xx=xx 影响子进程的环境变量
    thekll
        23
    thekll  
       2017-03-25 03:56:17 +08:00
    @lancegin 我上一条回复中间一句有问题,请忽略。(不经常用,有些概念就模糊了。)
    julyclyde
        24
    julyclyde  
       2017-03-25 08:41:06 +08:00
    @zzlyzq 错。是通过 export 为尚未启动的子进程准备初始环境变量
    lancegin
        25
    lancegin  
    OP
       2017-03-25 11:51:51 +08:00
    @julyclyde 请问下,如果在用户下的 bashrc 中 export 了环境变量,那重开一个 shell 的时候为什么也无效? login 的时候不是应该要加载一次 bashrc 的吗
    shalk
        26
    shalk  
       2017-03-25 12:34:21 +08:00
    @lancegin 参考 pyenv rvm 等 一些包管理工具的做法;

    curl url | bash -

    之后,修改了 bashrc , 或者提示你 把一些内容加到 bashrc 里,但是当前 shell 不会生效。

    所以需要,重开窗口,或者 exec $SHELL -l
    lancegin
        27
    lancegin  
    OP
       2017-03-25 12:49:31 +08:00
    @shalk 嗯 我现在将脚本中的 source 语句删掉了 执行脚本完之后抛出一个 source bashrc 的提醒
    julyclyde
        28
    julyclyde  
       2017-03-25 13:17:04 +08:00
    @lancegin 你“重开”的那个 shell 是怎么开的? man bash 看 INVOCATION 那一段核对一下具体是哪一种
    lancegin
        29
    lancegin  
    OP
       2017-03-26 01:19:15 +08:00 via iPhone
    @julyclyde 后来发现是 zsh 导致,默认加载了 zshrc ,我在 zshrc 里面 source 了 bashrc 就没问题了
    julyclyde
        30
    julyclyde  
       2017-03-26 21:28:30 +08:00
    @lancegin 不错,总算是找到原因并解决了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3535 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 04:53 · PVG 12:53 · LAX 21:53 · JFK 00:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.