Linux環境變數問題彙總
測試好的指令碼放到 crontab 裡就報錯: 找不到命令
寫好一個指令碼,測試沒有問題,然後放到crontab 想要定時執行,但是總是報錯,去看日誌的話顯示某些命令找不到,這種一般都是因為PATH環境變數變了導致的
自己在shell命令列下測試的時候當前環境變數就是這個使用者的環境變數,可以通過命令:env 看到,指令碼放到crontab 裡面後一般都加了sudo 這個時候 env 變了。比如你可以在命令列下執行 env 和 sudo env 比較一下就發現他們很不一樣
為了解決這個問題 sudo有一個引數 -E (–preserver-env)就是為了解決這個問題的。
這個時候再比較一下
- env
- sudo env
- sudo -E env
大概就能理解這裡的區別了
同樣一個命令ssh執行不了, 報找不到命令
比如:
ssh user@ip ” ip a ” 報錯: bash: ip: command not found
但是你要是先執行 ssh user@ip 連上伺服器後,再執行 ip a 就可以,這裡是同一個命令通過兩種不同的方式但是環境變數也不一樣了。
同樣想要解決這個問題的話可以先 ssh 連上伺服器,再執行 which ip ; env | grep PATH
$ which ip
/usr/sbin/ip
$ env | grep PATH
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
很明顯這裡因為 ip在/usr/sbin下,而/usr/sbin又在PATH變數中,所以可以找到。
那麼接下來我們看看
$ssh user@ip "env | grep PATH"
PATH=/usr/local/bin:/usr/bin
很明顯這裡的PATH比上面的PATH短了一截,/usr/sbin也沒有在裡面,所以/usr/sbin 下的ip命令自然也找不到了,這裡雖然都是同一個使用者,但是他們的環境變數還不一樣,有點出乎我的意料之外。
主要原因是我們的shell 分為login shell 和 no-login shell , 先ssh 登陸上去再執行命令就是一個login shell,Linux要為這個終端分配資源。
而下面的直接在ssh 裡面放執行命令實際上就不需要login,所以這是一個no-login shell.
login shell 和 no-login shell又有什麼區別呢?
- login shell載入環境變數的順序是:① /etc/profile ② ~/.bash_profile ③ ~/.bashrc ④ /etc/bashrc
- 而non-login shell載入環境變數的順序是: ① ~/.bashrc ② /etc/bashrc
也就是nog-login少了前面兩步,我們先看後面兩步。
下面是一個 .bashrc 的內容:
[ ~]$ cat .bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
基本沒有什麼內容,它主要是去載入 /etc/bashrc 而他裡面也沒有看到sbin相關的東西
那我們再看non-login少的兩步: ① /etc/profile ② ~/.bash_profile
cat /etc/profile :
if [ "$EUID" = "0" ]; then
pathmunge /usr/sbin
pathmunge /usr/local/sbin
else
pathmunge /usr/local/sbin after
pathmunge /usr/sbin after
fi
這幾行程式碼就是把 /usr/sbin 新增到 PATH 變數中,正是他們的區別決定了這裡的環境變數不一樣。
用一張圖來表述他們的結構,箭頭代表載入順序,紅框代表不同的shell的初始入口:
像 ansible 這種自動化工具,或者我們自己寫的自動化指令碼,底層通過ssh這種non-login的方式來執行的話,那麼都有可能碰到這個問題,如何修復呢?
在 /etc/profile.d/ 下建立一個檔案:/etc/profile.d/my_bashenv.sh 內容如下:
$cat /etc/profile.d/my_bashenv.sh
pathmunge () {
if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
fi
}
pathmunge /sbin
pathmunge /usr/sbin
pathmunge /usr/local/sbin
pathmunge /usr/local/bin
pathmunge /usr/X11R6/bin after
unset pathmunge
complete -cf sudo
alias chgrp=`chgrp --preserve-root`
alias chown=`chown --preserve-root`
alias chmod=`chmod --preserve-root`
alias rm=`rm -i --preserve-root`
HISTTIMEFORMAT=`[%F %T] `
HISTSIZE=1000
export EDITOR=vim
export PS1=`
e[1;37m[e[me[1;32mue[me[1;33m@e[me[1;35mHe[m e[4m`pwd`e[me[1;37m]e[me[1;36me[m
$`
通過前面我們可以看到 /etc/bashrc 總是會去載入 /etc/profile.d/ 下的所有 *.sh 檔案,同時我們還可以在這個檔案中修改我們喜歡的 shell 配色方案和環境變數等等
BASH
1、互動式的登入shell (bash –il xxx.sh)
載入的資訊:
/etc/profile
~/.bash_profile( -> ~/.bashrc -> /etc/bashrc)
~/.bash_login
~/.profile
2、非互動式的登入shell (bash –l xxx.sh)
載入的資訊:
/etc/profile
~/.bash_profile ( -> ~/.bashrc -> /etc/bashrc)
~/.bash_login
~/.profile
$BASH_ENV
3、互動式的非登入shell (bash –i xxx.sh)
載入的資訊:
~/.bashrc ( -> /etc/bashrc)
4、非互動式的非登入shell (bash xxx.sh)
載入的資訊:
$BASH_ENV
SH
1、互動式的登入shell
載入的資訊:
/etc/profile
~/.profile
2、非互動式的登入shell
載入的資訊:
/etc/profile
~/.profile
3、互動式的非登入shell
載入的資訊:
$ENV
練習驗證一下bash、sh和login、non-login
- sudo ll 或者 sudo cd 是不是都報找不到命令
- 先sudo bash 然後執行 ll或者cd就可以了
- 先sudo sh 然後執行 ll或者cd還是報找不到命令
- sudo env | grep PATH 然後 sudo bash 後再執行 env | grep PATH 看到的PATH環境變數不一樣了
4、非互動式的非登入shell
載入的資訊:
nothing
export命令的作用
Linux 中export是一種命令工具通過export命令把shell變數中包含的使用者變數匯入給子程式.預設情況下子程式僅會繼承父程式的環境變數,子程式不會繼承父程式的自定義變數,所以需要export讓父程式中的自定義變數變成環境變數,然後子程式就能繼承過來了。
我們來看一個例子, 有一個變數,名字 abc 內容123 如果沒有export ,那麼通過bash建立一個新的shell(新shell是之前bash的子程式),在新的shell裡面就沒有abc這個變數, export之後在新的 shell 裡面才可以看到這個變數,但是退出重新login後(產生了一個新的bash,只會載入env)abc變數都不在了
$echo $abc
$abc="123"
$echo $abc
123
$bash
$echo $abc
$exit
exit
$export abc
$echo $abc
123
$bash
$echo $abc
123
一些常見問題
執行好好地shell 指令碼換臺伺服器就:source: not found
source 是bash的一個內建命令(所以你找不到一個/bin/source 這樣的可執行檔案),也就是他是bash自帶的,如果我們執行指令碼是這樣: sh shell.sh 而shell.sh中用到了source命令的話就會報 source: not found
這是因為bash 和 sh是兩個東西,sh是 POSIX shell,你可以把它看成是一個相容某個規範的shell,而bash是 Bourne-Again shell script, bash是 POSIX shell的擴充套件,就是bash支援所有符合POSIX shell的規範,但是反過來就不一定了,而這裡的 source 恰好就是 bash內建的,不符合 POSIX shell的規範(POSIX shell 中用 . 來代替source)
在centos執行好好的指令碼放到Ubuntu上就不行了,報語法錯誤
同上,如果到ubuntu上用 bash shell.sh是可以的,但是sh shell.sh就報語法錯誤,但是在centos上執行:sh或者bash shell.sh 都可以通過。 在centos上執行 ls -lh /usr/bin/sh 可以看到 /usr/bin/sh link到了 /usr/bin/bash 也就是sh等同於bash,所以都可以通過不足為奇。
但是在ubuntu上執行 ls -lh /usr/bin/sh 可以看到 /usr/bin/sh link到了 /usr/bin/dash , 這就是為什麼ubuntu上會報錯
source shell.sh 和 bash shell.sh以及 ./shell.sh的區別
source shell.sh就在本shell中展開執行
bash shell.sh表示在本shell啟動一個子程式(bash),在子程式中執行 shell.sh (shell.sh中產生的一些環境變數就沒法帶回父shell程式了), 有讀 shell.sh 許可權就可以執行
./shell.sh 跟bash shell.sh類似,但是必須要求shell.sh有rx許可權,然後根據shell.sh前面的 #! 後面的指示來確定用bash還是sh
$cat test.sh
echo
$$
$echo
$$
2299
$source test.sh
2299
$bash test.sh
4037
$./test.sh
4040
如上例項,只有source的時候程式ID和bash程式ID一樣,其它方式都建立了一個新的bash程式,所以ID也變了
參考文章:
什麼是互動式登入 Shell what-is-interactive-and-login-shell
相關文章
- 一、Windows 環境搭建問題彙總Windows
- 生產環境資料遷移問題彙總
- Linux 新增環境變數和刪除環境變數Linux變數
- 【Linux】環境變數!!!Linux變數
- Linux 環境變數Linux變數
- linux環境安裝——整理彙總Linux
- linux環境顯示全部環境變數Linux變數
- Linux環境變數配置Linux變數
- Linux常用環境變數Linux變數
- 關於環境變數設定的問題變數
- OpenMP 環境變數使用總結變數
- 環境變數{Linux環境(也稱為Shell環境)}(轉)變數Linux
- crontab定時任務環境變數使用問題變數
- linux java環境變數配置LinuxJava變數
- Linux配置環境變數$PATHLinux變數
- linux系統環境變數Linux變數
- Linux設定環境變數Linux變數
- linux配置jdk環境變數LinuxJDK變數
- [Linux] 檢視環境變數Linux變數
- linux 環境變數介紹Linux變數
- Linux - 新增PATH環境變數Linux變數
- linux配置java環境變數LinuxJava變數
- Linux 環境變數設定Linux變數
- linux工具配置環境變數Linux變數
- Linux下將PHP新增到環境變數,將Mysql加入環境變數。LinuxPHP變數MySql
- Linux 初級問題-3.符號連結和環境變數Linux符號變數
- linux基礎——shell變數(本地變數和環境變數)Linux變數
- 環境變數變數
- crontab定時任務環境變數丟失問題變數
- ORACLE_SID環境變數設定的問題Oracle變數
- Linux中bash shell環境變數Linux變數
- 修改linux下mysql環境變數LinuxMySql變數
- linux DISPLAY環境變數介紹Linux變數
- linux登入bash shell環境執行環境變數Linux變數
- 新手對於iPhone開發環境等入門問題解答彙總iPhone開發環境
- Linux有問必答:如何在Linux中修改環境變數PATHLinux變數
- Linux中修改環境變數及生效方法(永久、臨時)環境變數檢視Linux變數
- 簡述SHELL全域性環境變數與局變環境變數變數