完全解讀Linux環境變數

來源:互聯網
上載者:User

完全解讀Linux環境變數
一、概述

環境變數:bash shell用一個稱作“環境變數(environment variables)”的特性來儲存有關shell會話和工作環境的資訊,它允許你在記憶體中儲存資料,以便運行在shell上的程式和指令碼訪問,這些資料可以用來識別使用者、賬戶、系統、shell特性以及任何其他你需要儲存的資料。

shell中的環境變數有全域環境變數和局部環境變數,通過KV(variable=value)的形式聲明一個局部變數,export這個局部變數,則升級成為全域環境變數。既然shell分開來用,顯然兩者有區別,下面分開來討論。

1. 全域環境變數

特性:聲明一個全域環境變數,在當前shell進程以及子shell進程中可用,父shell進程中不可用,這裡的“可用”可以理解成父shell進程全域環境變數的一個copy,而不是繼承父類的全域環境變數兩者共用一份,因此子shell進程中對父shell進程的全域環境變數進行增、刪、該、查均無影響。

證明一:1)全域變數在當前shell可用、子shell可用,但是父shell進程不可用;2)子shell copy了父shell進程的全域環境變數的副本,因此子shell對變數的操作對父類透明

 

#!/bin/bash#父shell進程#       1. 聲明一個全域環境變數#       2. fork一個子shell進程#               在子shell進程中可以訪問父類定義的全域變數#               在子shell中修改或刪除(unset)父類定義的全域環境變數,對父進程沒有影響#               在子shell中增加一個全域環境變數,父類中是訪問不到的#       3. 父shell進程中訪問被子shell進程修改或刪除的全域環境變數,該變數值未改變#       4. 父shell進程訪問子類增加的子類全域環境變數:結果是訪問不到export testing="zhangsan"echo "father定義了一個全域變數,初始值為:testing=zhangsan"sh son.shecho "father訪問被子類修改的全域變數:$testing"echo "father訪問子類增加的全域變數:$sonTest"
#!/bin/bash#子shell進程echo "son訪問父類shell進程中定義的全域變數:$testing"testing="son zhangsan"echo "son修改了父類的全域變數:testing=$testing"export sonTest="son lizi"echo "son增加了子類全域變數:$sonTest"
[work@localhost global]$ sh father.sh father定義了一個全域變數,初始值為:testing=zhangsanson訪問父類shell進程中定義的全域變數:zhangsanson修改了父類的全域變數:testing=son zhangsanson增加了子類全域變數:son lizifather訪問被子類修改的全域變數:zhangsanfather訪問子類增加的全域變數:

 

證明二:登入shell fork一個子shell進程,該子shell進程export一個全域環境變數,執行完成後在登入shell中沒有該變數

 

 

#!/bin/bash#登入shell fork一個子shell進程#       子shell進程聲明一個全域環境變數#       子shell執行完成之後,退出到登入shell#       登入shell訪問不到該變數export userName="zhangsan"
執行該指令碼,執行完成後訪問變數,沒有值。
[work@localhost global]$ sh var.sh [work@localhost global]$ echo $userName[work@localhost global]$ 

 

2. 局部環境變數

特性:當前shell進程可用,父、子shell進程不可用

證明:父進程定義局部變數,子進程訪問不到;子進程定義局部變數,父進程訪問不到

 

#!/bin/bashfatherVar="father var"echo "father定義的局部變數:$fatherVar"sh son.shecho "son定義的局部變數:$sonVar"
#!/bin/bashecho "son訪問fanther定義的局部變數:$fatherVar"sonVar="son var"echo "son定義的局部變數:$sonVar"
[work@localhost local]$ sh father.sh father定義的局部變數:father varson訪問fanther定義的局部變數:son定義的局部變數:son varson定義的局部變數:

 

3. 總結

1. 全域環境變數:當前shell進程及子進程可用,父shell進程不可用,子進程對變數的修改對當前shell來說透明無影響;

2. 局部環境變數:當前shell進程可用,父進程、子進程均不可用;

3. 環境變數存在記憶體當中,斷電後消失,如果想要在下一次系統加電後還可以訪問:

a. 如果這個變數是系統層級的(所有使用者共用),則可以在/etc/profile中export;

b. 如果這個變數只對目前使用者有效,則可以在~/.bash_profile(或者~./bash_login,或者~./profile,或者~./bashrc,或者/etc/bashrc)中export;

補充:本節討論主要是fork進程方式,不包括source和exec,三種方式的差異在後面進行討論;

二、啟動shell

環境變數存放在記憶體當中,斷電後消失。但是你會發現類似USER、PATH、LOGNAME、HOSTNAME這些環境變數,只要系統一啟動就存在了。這是為什嗎?

作業系統因該具備至少5個功能:記憶體管理、檔案系統管理、進程管理、裝置管理(硬體)和使用者介面管理,這裡的使用者介面不能理解成init 5啟動介面功能或類似windows的介面,而是使用者和系統核心互動的介面,即核心提供給外界的一組提供者,所以在系統啟動的時候,啟動shell就是為此而生,他向使用者提供了一組和Linux kernel互動的介面。

啟動shell隨著系統的啟動而啟動,根據表現可以將其理解成後續登入shell、互動shell、非互動shell的頂級父shell環境,因此在啟動shell中聲明的全域環境變數,後續的所有shell都可以訪問到,毫無疑問,局部變數例外。

啟動shell啟動之後,他首先會到/etc/profile中讀取命令並執行,讀取執行該檔案,主要做了兩件事:

1. 定義並 聲明全域的環境變數,export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL,所有的shell進程都可以訪問到這些變數;

2. 到/etc/profile.d目錄中執行該目錄下的應用開機檔案,這個目錄集中存放了一些應用的開機檔案,這些應用隨著系統啟動而啟動,譬如vim、less等,類似於windows中的啟動項中定義的一些開機自啟動並執行軟體;

/etc/profile.d目錄下的內容和/etc/profile的內容如下:

 

# /etc/profile# System wide environment and startup programs, for login setup# Functions and aliases go in /etc/bashrc# It's NOT a good idea to change this file unless you know what you# are doing. It's much better to create a custom.sh shell script in# /etc/profile.d/ to make custom changes to your environment, as this# will prevent the need for merging in future updates.pathmunge () {    case ":${PATH}:" in        *:"$1":*)            ;;        *)            if [ "$2" = "after" ] ; then                PATH=$PATH:$1            else                PATH=$1:$PATH            fi    esac}if [ -x /usr/bin/id ]; then    if [ -z "$EUID" ]; then        # ksh workaround        EUID=`id -u`        UID=`id -ru`    fi    USER="`id -un`"    LOGNAME=$USER    MAIL="/var/spool/mail/$USER"fi# Path manipulationif [ "$EUID" = "0" ]; then    pathmunge /sbin    pathmunge /usr/sbin    pathmunge /usr/local/sbinelse    pathmunge /usr/local/sbin after    pathmunge /usr/sbin after    pathmunge /sbin afterfiHOSTNAME=`/bin/hostname 2>/dev/null`HISTSIZE=1000if [ "$HISTCONTROL" = "ignorespace" ] ; then    export HISTCONTROL=ignorebothelse    export HISTCONTROL=ignoredupsfiJAVA_HOME=/usr/java/jdk1.7.0_75CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jarPATH=$PATH:$JAVA_HOME/binexport PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL# By default, we want umask to get set. This sets it for login shell# Current threshold for system reserved uid/gids is 200# You could check uidgid reservation validity in# /usr/share/doc/setup-*/uidgid fileif [ $UID -gt 199 ] && [ "`id -gn`" = "`id -un`" ]; then    umask 002else    umask 022fifor i in /etc/profile.d/*.sh ; do    if [ -r "$i" ]; then        if [ "${-#*i}" != "$-" ]; then            . "$i"        else            . "$i" >/dev/null 2>&1        fi    fidoneunset iunset -f pathmunge

 

三、登入shell

無論是哪一個使用者登入系統,printenv列印的全域環境變數都是一樣的,因為這些值在啟動shell中定義完成。但是你會發現,實際上存在不一樣,這會給人造成錯覺,進而無法理解登入shell的真正含義。

1. 區別啟動shell和登入shell

系統啟動完成之後,緊接著就是使用者登入訪問了。不同的使用者登入系統,printenv的結果是不一樣的,也就是說不同的使用者有不同的的shell進程環境,這也間接說明登入shell和啟動shell是不一樣,登入shell是頂級環境。先來驗證一下,再來進行說明。

驗證一:不同使用者登入,其全域環境變數不一樣,此處選擇root和work使用者,測試全域環境變數PATH

步驟一:work賬戶登入,echo $PATH > /home/work/var.path

步驟二:切換使用者以及環境到root,su - root,echo $PATH >> /home/work/var.path

步驟三:cat /home/work/var.path,比較兩行值,執行結果如下所示

 

[work@localhost ~]$ echo $PATH > /home/work/xx.path[work@localhost ~]$ su - root Password: [root@localhost ~]# echo $PATH >> /home/work/xx.path[root@localhost ~]# cat /home/work/xx.path /usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/java/jdk1.7.0_75/bin:/home/work/bin/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/java/jdk1.7.0_75/bin:/root/bin

 

2. 登入shell詳解

 

登入shell在啟動shell之上又加入了個人化,不同使用者獲得的登入環境是不一樣的。除root使用者之外,Linux上其他使用者的主目錄是/home/xxx,要進行個人化,必然在此做文章。

登入shell的入口,~/.bash_profile檔案。

a. .bash_profile檔案

當你輸入使用者名稱和密碼登入系統的時候,啟動shell進程會fork一個登入shell進程,這個登入shell進程會到當前登入使用者的主目錄下順序讀取(如果存在)檔案~/.bash_profile、~/.bash_login、~/.profile 中的指令並執行,需要注意的是這三個檔案不一定都存在(我的系統centos 2.6.32中就只存在.bash_profile),如果存在多個,則按照列出順序進行讀取指令並執行。

讀取到.bash_profile主要做了兩件事情,一件是source(最後一節會有source的詳解)~/.bashrc這個檔案,另一件是重新export PATH,詳細內容如下。

 

# .bash_profile# Get the aliases and functionsif [ -f ~/.bashrc ]; then        . ~/.bashrcfi# User specific environment and startup programsPATH=$PATH:$HOME/binexport PATH

 

b. .bashrc檔案由此,可知不同使用者的環境變數PATH不一致的原因。但是source ~/.bashrc這個檔案又做了什麼事情?

 

.bashrc檔案也做了兩件事,一件是定義一些別名(定義別名,你可以在當前shell中任意使用,類似定義局部環境變數),另一件事是source了/etc/bashrc檔案。

 

# .bashrc# User specific aliases and functionsalias rm='rm -i'alias cp='cp -i'alias mv='mv -i'# Source global definitionsif [ -f /etc/bashrc ]; then        . /etc/bashrcfi

 

c. /etc/bashrc檔案

 

/etc/bashrc又TM的做了什麼事情?在/etc/bashrc檔案中也做了兩件事情,一件事情是定義了一些局部變數(沒有export,登入shell可用,其fork的子shell均不能訪問),還根據UID設定了umask的許可權;另一件事情是又讀取並執行了一次/etc/profile.d目錄下的檔案,這一步和啟動shell有重複,雖然看似重複但實際上是有必要的原因,這裡了需要和互動shell(下一節講解)結合。

至此,使用者登入環境初始化完成,所有使用者公用的全域變數有了,不同使用者個人化的全域變數也準備好了,和自己有關係的局部變數也準備好了,萬事俱備,使用者可以進行系統操作了。

 

# /etc/bashrc# System wide functions and aliases# Environment stuff goes in /etc/profile# It's NOT a good idea to change this file unless you know what you# are doing. It's much better to create a custom.sh shell script in# /etc/profile.d/ to make custom changes to your environment, as this# will prevent the need for merging in future updates.# are we an interactive shell?if [ "$PS1" ]; then  if [ -z "$PROMPT_COMMAND" ]; then    case $TERM in    xterm*)        if [ -e /etc/sysconfig/bash-prompt-xterm ]; then            PROMPT_COMMAND=/etc/sysconfig/bash-prompt-xterm        else            PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'        fi          ;;      screen)        if [ -e /etc/sysconfig/bash-prompt-screen ]; then            PROMPT_COMMAND=/etc/sysconfig/bash-prompt-screen        else            PROMPT_COMMAND='printf "\033]0;%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'        fi          ;;      *)          [ -e /etc/sysconfig/bash-prompt-default ] && PROMPT_COMMAND=/etc/sysconfig/bash-prompt-default        ;;        esac  fi    # Turn on checkwinsize  shopt -s checkwinsize  [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "  # You might want to have e.g. tty in prompt (e.g. more virtual machines)  # and console windows  # If you want to do so, just add e.g.  # if [ "$PS1" ]; then  #   PS1="[\u@\h:\l \W]\\$ "  # fi  # to your custom modification shell script in /etc/profile.d/ directoryfiif ! shopt -q login_shell ; then # We're not a login shell    # Need to redefine pathmunge, it get's undefined at the end of /etc/profile    pathmunge () {        case ":${PATH}:" in            *:"$1":*)                ;;            *)                if [ "$2" = "after" ] ; then                    PATH=$PATH:$1                else                    PATH=$1:$PATH                fi        esac    }    # By default, we want umask to get set. This sets it for non-login shell.    # Current threshold for system reserved uid/gids is 200    # You could check uidgid reservation validity in    # /usr/share/doc/setup-*/uidgid file    if [ $UID -gt 199 ] && [ "`id -gn`" = "`id -un`" ]; then       umask 002    else       umask 022    fi    # Only display echos from profile.d scripts if we are no login shell    # and interactive - otherwise just process them to set envvars    for i in /etc/profile.d/*.sh; do        if [ -r "$i" ]; then            if [ "$PS1" ]; then                . "$i"            else                . "$i" >/dev/null 2>&1            fi        fi    done    unset i    unset pathmungefi
四、互動shell

 

init 3登入系統之後,你在命令列介面輸入的指令實際上都是在登入shell的環境中執行,你可以訪問登入shell中聲明的任意局部變數。但是當你輸入bash顯式啟動一個互動shell的時候(命令列介面給你的感覺是敲了一下斷行符號,剩下的好像什麼也沒發生),你會發現粗大事了,還是在一模一樣的介面,但是你發現訪問不了剛才可以訪問到的局部變數了。這是因為登入shell fork了一個子shell的環境,而子shell環境是不能訪問父shell環境的局部變數的。

1. 區別登入shell和互動shell

證明一:互動shell不是登入shell,而是登入shell fork的一個子shell進程

步驟一:登入系統後,定義一個局部變數testing="zhangsan",命令列輸入echo $testing,測試可以訪問得到;

步驟二:命令列輸入bash啟動一個互動shell,訪問剛才定義的局部變數,echo $testing,測試不可以訪問;

步驟三:命令列輸入exit指令,退出互動式shell,再次訪問echo $testing,發現可以訪問;

 

[work@localhost ~]$ testing="zhangsan"[work@localhost ~]$ echo $testingzhangsan[work@localhost ~]$ bash[work@localhost ~]$ echo $testing[work@localhost ~]$ exitexit[work@localhost ~]$ echo $testingzhangsan[work@localhost ~]$ 
由此可見,互動shell是登入shell的子進程。

 

2. 互動shell詳解

 

當你在命令列輸入bash指令顯式進入互動式shell環境的時候,系統發生了什嗎?不像啟動shell和登入shell,互動式shell沒有發生在系統啟動的時候,也沒有發生在使用者登入的時候,這時候系統已經啟動,使用者已經登入,之前的讀取的檔案執行的指令和結果都已經在記憶體中存在了,那麼互動式shell做了那些事情呢?

互動shell是登入shell的子進程,因此他擁有了登入shell聲明的所有全域環境變數(當然也擁有啟動shell聲明的全域環境變數),但是他沒有登入shell聲明的局部變數,也沒有登入shell聲明的一些個人化例如umask、alias等,那麼目前使用者沒有任何理由開啟一個互動式shell,個人化丟失,每次開啟都要重新搞一遍個人化,太TM麻煩了,這種功能你用嗎?有毛用啊?

請不要激動,存在即合理。

互動式shell啟動第一步,就是檢查目前使用者的主目錄下是否有.bashrc檔案(這個檔案上一節有詳細的描述),存在則讀取並執行檔案中的指令。這個檔案的作用不就是聲明局部變數和個人化配置的的嗎?他第一步就是定義別名等,然後source /etc/bashrc檔案,/etc/bashrc檔案一開始定義了使用者的局部變數,接著又載入並執行了/etc/profile.d目錄下的應用開機檔案。

你會驚奇的發現,開啟一個互動shell,和一個剛剛登入的登入shell環境一模一樣!乾淨、純粹、原始,就像少女一樣啊!激動吧?!還有更激動的事情,不要忘了,子shell可以訪問父shell的全域環境變數,但是父shell不能訪問子shell的環境,也就意味著你在互動式shell中所做的壞事永遠不會影響到父shell環境(當然你不要手賤去改設定檔,改了設定檔就是持久化了操作內容,而不是更改記憶體內容,系統斷電後再啟動負載檔案還是會還原出來的),當然如果想父shell環境也能感受到,則需要修改檔案了。

實際上你也能感受到,登入shell其實就是第一個互動shell,一問一答,使用者問系統答,很友好啊,有求必應!

五、非互動shell

非互動shell就沒有那麼友好了,這也正是非互動shell存在的核心價值,不需要使用者來幹預,自動完成指令碼中規定的指令。

因此,簡單來說,非互動shell,即是執行shell指令碼。

當然,非互動式shell作為互動shell fork出來的子進程,擁有父進程所有的全域環境變數(再次申明:不擁有父進程的局部環境變數,你在指令碼中是訪問不到的),他不會再像互動shell那樣到使用者主目錄下去讀取執行.bashrc檔案給自己做個人化,最簡單直接的例子就是ls的alias指令ll,你在指令碼中使用該指令,就會收到”run.sh: line 3: ll: command not found“的錯誤提示,如以下程式碼範例。

 

[work@localhost env]$ alias -p |grep llalias ll='ls -l --color=auto'[work@localhost env]$ cat run.sh #!/bin/bashll[work@localhost env]$ sh run.sh run.sh: line 3: ll: command not found[work@localhost env]$ echo $?127[work@localhost env]$ lltotal 16drwxrwxr-x. 2 work work 4096 Apr 23 06:56 aliasdrwxrwxr-x. 2 work work 4096 Apr 23 05:43 globaldrwxrwxr-x. 2 work work 4096 Apr 23 05:59 local-rw-rw-r--. 1 work work   16 Apr 23 07:59 run.sh

要想對非互動是shell進行個人化,系統也提供了”介面“,就是環境變數BASH_ENV,當啟動一個非互動式shell的時候,系統會檢查這個環境變數來查看要載入執行的開機檔案,因此你可以自訂一個檔案路徑然後export BASH_ENV,從而達到你想要的目的和結果,這也是傳說中的BASH_ENV漏洞,但是這個漏洞在2014.09月被修複了,在此就不再進行贅述了。

1)BASH_ENV漏洞簡單利用:點擊開啟連結

2)BASH_ENV漏洞修複介紹:點擊開啟連結

六、fork、source和exec

shell編程的時候,往往不會把所有功能都寫在一個指令碼中,這樣太不好維護了,需要多個指令檔協同工作。那麼問題來了,在一個指令碼中怎麼調用其他的指令碼呢?有三種方式,分別是fork、source和exec。

1. fork

fork其實最麻煩,他是從當前shell進程中fork一個子shell進程來完成調用,上文所述的所有情況都是fork調用形式,簡單總結,就是父shell進程的全域環境變數copy一份給子shell進程,因為是拷貝,所以子shell進程對這一份變數的所有操對父shell進程無影響,父進程的局部變數不會被子shell進程訪問到;子shell的全域環境變數自對自己和自己的子shell進程有用,對父shell進程屏蔽,子shell的局部變數也只對當前shell進程有效。

另外,fork調用其實就是在一個指令碼中調用另一個指令碼,被呼叫指令碼執行完成之後返回給父shell進程,父shell進程繼續執行剩下的指令,其中所涉及的慶幸上文已經基本全部覆蓋,此處示範一下fork調用的範例程式碼。

 

#!/bin/bashecho "父shell進程開始執行"sh son.sh #父shell fork子shell環境執行另一個指令碼echo "父shell進程執行完畢"
#!/bin/bashecho "子shell被調用"
[work@localhost fork]$ sh father.sh 父shell進程開始執行子shell被調用父shell進程執行完畢

 

2. source

source調用,是把被呼叫指令碼載入到當前的shell環境中來執行,就好像是在一個指令碼裡面運行一樣,他們的定義的局部變數共用,在同一個進程中,如以下樣本。

 

#!/bin/bash. ./son.sh  #通過source方式將son.sh載入到當前shell環境中echo "father訪問son中定義的局部變數:$sonVar"
#!/bin/bashsonVar="son var"echo "son定義了一個變數:sonVar=$sonVar"
[work@localhost source]$ sh father.sh son定義了一個變數:sonVar=son varfather訪問son中定義的局部變數:son var

 

3. exec

exec調用,也是fork一個子shell環境來執行被呼叫指令碼,但是父shell環境的執行權會被剝奪,也就是執行權被交給了被呼叫指令碼,父shell環境不再擁有執行權,無論父shell指令碼中的指令是否執行完成,都不在被執行,隨著子shell進程的結束而結束。

 

#!/bin/bashecho "父shell開始執行"exec sh son.shecho "父shell完成執行,但是這句話不會被執行"
#!/bin/bashecho "子shell被父shell exec調用,執行權已經被搶佔過來了,不會在交回給父shell進程"
[work@localhost exec]$ sh father.sh 父shell開始執行子shell被父shell exec調用,執行權已經被搶佔過來了,不會在交回給父shell進程

 

關於fork、source和exec網上已經有很多介紹了,要是這裡沒有看明白,可以搜尋“fork、source和exec”。

七、環境變數PATH

什麼是環境變數PATH?這個環境變數,在調用shell指令碼的時候很有用,麻煩和問題也主要集中在這裡,PATH環境變數定義了各種shell環境搜尋執行指令的路徑,就像windows上的path環境變數一樣。執行自己寫的指令碼,如果你不想進入到指令碼目錄或者輸入全路徑,那麼你直接把你的指令碼拷貝到PATH下面的任意一個目錄即可,但是這樣太侵入了,不優雅,下面簡單介紹一種比較優雅的開發技巧。

開發技巧:便捷執行指令

通過軟串連和別名alias來讓自訂指令碼可以在當前shell環境中任意被調用。

第一步:查看PATH環境變數,隨便選一個目前使用者有操作許可權的一個出來,本處選擇/home/work/bin

第二步:寫一個測試指令碼run.sh,放在/home/work/shell/myCodes目錄下,裡面只有一句指令”echo $0"列印當前執行指令碼名稱,然後做一個軟串連ln -s /home/work/shell/myCodes/run.sh /home/work/bin/run

第三步:定義別名,先alias -p看一下,不要定義重複了,然後定義別名alias run="sh run",完成

結果:你不用在進入到指令碼所在的目錄執行指令碼,在任意目錄執行run指令就可以調用/home/work/shell/myCodes/run.sh指令碼,而且支援tab鍵補全,是不是很NB!

 

[work@localhost myCodes]$ lsrun.sh[work@localhost myCodes]$ cat run.sh #!/bin/bashecho $0[work@localhost myCodes]$ pwd/home/work/shell/myCodes[work@localhost myCodes]$ cat run.sh #!/bin/bashecho $0[work@localhost myCodes]$ ll /home/work/bin/run  lrwxrwxrwx. 1 work work 31 Apr 23 09:57 /home/work/bin/run -> /home/work/shell/myCodes/run.sh[work@localhost myCodes]$ alias -p |grep runalias run='run'[work@localhost myCodes]$ cd /home/work/[work@localhost ~]$ runi'm bash_env/home/work/bin/run

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.