分类 默认分类 下的文章

在ubuntu服务器中安装 webdriver chrome 的方法可参考:https://blog.qqvbc.com/default/637.html

安装后执行(默认端口是9515):

#如果和PHP服务器不在一个机器上,需要加上allowed-ips参数,允许远程IP访问本地端口
chromedriver [--allowed-ips=192.168.8.29]

PHP使用composer安装php-webdriver/webdriver库文件:

以下是PHP代码调用服务器运行的webdriver服务端口在服务器中渲染网页,并截图的代码:

require_once 'autoload.php';

use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
...
public function actionTest($text=null)
    {
        $capabilities = DesiredCapabilities::chrome();
        $host = 'http://127.0.0.1:9515';
        $options = new ChromeOptions();
        $options->addArguments(
            [
                  '--no-sandbox',                        // 解决DevToolsActivePort文件不存在的报错
                 'window-size=1920x1080',               // 指定浏览器分辨率
                //   '--disable-gpu',                       // 谷歌文档提到需要加上这个属性来规避bug
                //   '--hide-scrollbars',                   // 隐藏滚动条, 应对一些特殊页面
                //  'blink-settings=imagesEnabled=false',  // 不加载图片, 提升速度
                // '--ignore-certificate-errors',
                // '--ignore-ssl-errors',
                '--headless',                          // 浏览器不提供可视化页面
            ]
        );
        $options->setExperimentalOption('useAutomationExtension',false);
        $options->setExperimentalOption('excludeSwitches', ['enable-automation', 'enable-logging']);
        $capabilities->setCapability(ChromeOptions::CAPABILITY, $options);

        $driver = RemoteWebDriver::create($host, $capabilities);
        $driver->get('https://www.baidu.com/');
        $title = $driver->getTitle();
        $content = $driver->getPageSource();
        $driver->takeScreenshot('test.png');
        var_dump($title);
}


    /**
     * 获取页面中的一个元素
     * @param RemoteWebDriver $driver
     * @param WebDriverBy $query
     * @param int $timeout
     * @return RemoteWebElement|null
     */
    public static function getElement(RemoteWebDriver $driver, WebDriverBy $query, int $timeout=30)
    {
        while ($timeout>0) {
            try {
                return $driver->findElement($query);
            } catch (\Exception $e) {
                $timeout--;
                sleep(1);
            }
        }
        return null;
    }


        //上传input控件
        $query = WebDriverBy::cssSelector('#app > div > div > div.upload-container > div.video-uploader-container.upload-area > div.upload-wrapper > div > input');
        //上传多个文件
        if ($el = Account::getElement($this->driver, $query)) {
            //sendKeys方法用于向输入控件输入文字,也可用于向文件控件指定要上传的文件路径,可上传多个文件的控件可使用换行来分隔文件列表
            $el->sendKeys(implode("\n", $fileList));
        }
....

截图后发现图片上的中文字体没有正常显示,而是一些方框,是因为服务器系统中没有中文字体的原因
在WIN系统中找一些中文字体上传到服务器 /usr/share/fonts/ 中执行如下命令后,即可解决

 mv msyh*.ttc /usr/share/fonts/
 mkfontscale 
 mkfontdir 
 fc-cache -fv

通过在服务器安装webdriver + chrome,可以实现很多功能,模拟人为操作

wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
dpkg -i --force-depends google-chrome-stable_current_amd64.deb
然后报出了如下错误:
很多依赖没有安装

#接下来,解决依赖的安装,输入命令:
apt-get install -f

#然后再重新执行命令:
dpkg -i --force-depends google-chrome-stable_current_amd64.deb

#果然没出意外,安装成功

#安装xvfb,这个是为了让chrome可以无界面运行。命令:
apt-get install xvfb

#安装chromedriver,首先获取chromedriver的最新版本信息:
LATEST=$(wget -q -O - http://chromedriver.storage.googleapis.com/LATEST_RELEASE))
wget http://chromedriver.storage.googleapis.com/$LATEST/chromedriver_linux64.zip
unzip chromedriver_linux64.zip
chmod a+x chromedriver
mv chromedriver /usr/bin/


## 测试是否安装成功
pip3 install selenium
vim test.py
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_opt = Options()  # 创建参数设置对象.
chrome_opt.add_argument('--headless')  # 无界面化.
chrome_opt.add_argument('--disable-gpu')  # 配合上面的无界面化.
chrome_opt.add_argument('--window-size=1366,768')  # 设置窗口大小, 窗口大小会有影响.
chrome_opt.add_argument("--no-sandbox") #使用沙盒模式运行
# 创建Chrome对象并传入设置信息.
browser = webdriver.Chrome(chrome_options=chrome_opt)
url = "https://www.baidu.com/"
browser.get(url)
print(browser.page_source)
browser.quit()
python test.py

如果界面里成功输出了百度首页的html代码就说明成功了。

有时候一些静态的文件放在另一个非站内的目录中,或者URL中并不是原来的目录

如下配置:注意 break 关键字;

location ~* ^/download/(video|image)/ {
  root /data/files;
  default_type application/octet-stream;
  rewrite ^/download/(.*)$ /$1 break;
    if (!-e $request_filename) {
      return 405;
    }
}

以下内容转摘自:https://cloud.tencent.com/developer/article/1488296

当我们在浏览器中链接一个文件的下载地址(音视频/图片)的时候,本意是想让浏览器执行下载操作,但默认是访问了一个在线预览的页面进行展示。

这个时候,通过标签的 download 属性实现下载是其中常见也是比较简单的一种方法。
download属性是 HTML5 中
标签新增的一个属性,此属性会强制触发下载操作,指示浏览器下载 URL 而不是导航到它,并提示用户将其保存为本地文件,例如:

<a href="result.png" download="filename">download</a>

如果缺少download属性,点击 "download" 会直接变成预览图片,当添加download属性后则会触发图片的下载。

兼容性还好,除了IE的所有版本不支持,其它都支持了:https://caniuse.com/#search=download

文件命名问题

download属性不仅可以触发下载,也能指定下载文件名:

<a href="test.png" download="joker.png">下载</a>

如果下载文件的后缀与源文件保持一致,可以设置缺省文件名:

<a href="test.png" download="joker">下载</a>

`
download 属性与文件名直接相关联。

遗憾的是,download属性目前仅适用于同源 URL,即如果需要下载的资源地址是跨域的,download属性就会失效。
注:Chrome65 之前是支持 download 属性触发文件跨域下载的,之后则严格遵循同源策略,无法再通过 download 属性触发跨域资源的下载。而 FireFox 一直不支持跨域资源的 download 属性下载。

nginx文件结构

首先我们先简单了解 nginx 的文件结构,nginx 的 HTTP 配置主要包括三个区块,结构如下:

Global: nginx 运行相关
Events: 与用户的网络连接相关
http
    http Global: 代理,缓存,日志,以及第三方模块的配置
    server
        server Global: 虚拟主机相关
        location: 地址定向,数据缓存,应答控制,以及第三方模块的配置

从上面展示的 nginx 结构中可以看出 location 属于请求级别配置,这也是我们最常用的配置。

配置 location 块

location 语法
Location 块通过指定模式来与客户端请求的URI相匹配。
Location基本语法:

匹配 URI 类型,有四种参数可选,当然也可以不带参数。
命名location,用@来标识,类似于定义goto语句块。
location [ = | ~ | ~* | ^~ ] /URI { … }
location @/name/ { … }
location匹配命令解释

参数    解释
空    location 后没有参数直接跟着 标准 URI,表示前缀匹配,代表跟请求中的 URI 从头开始匹配。
=    用于标准 URI 前,要求请求字符串与其精准匹配,成功则立即处理,nginx停止搜索其他匹配。
^~    用于标准 URI 前,并要求一旦匹配到就会立即处理,不再去匹配其他的那些个正则 URI,一般用来匹配目录
~    用于正则 URI 前,表示 URI 包含正则表达式, 区分大小写
~*    用于正则 URI 前, 表示 URI 包含正则表达式, 不区分大小写
@    @ 定义一个命名的 location,@ 定义的locaiton名字一般用在内部定向,例如error_page, try_files命令中。它的功能类似于编程中的goto。

location匹配顺序

nginx有两层指令来匹配请求 URI 。第一个层次是 server 指令,它通过域名、ip 和端口来做第一层级匹配,当找到匹配的 server 后就进入此 server 的 location 匹配。

location 的匹配并不完全按照其在配置文件中出现的顺序来匹配,请求URI 会按如下规则进行匹配:

先精准匹配 = ,精准匹配成功则会立即停止其他类型匹配;
没有精准匹配成功时,进行前缀匹配。先查找带有 ^~ 的前缀匹配,带有 ^~ 的前缀匹配成功则立即停止其他类型匹配,普通前缀匹配(不带参数 ^~ )成功则会暂存,继续查找正则匹配;
= 和 ^~ 均未匹配成功前提下,查找正则匹配 ~ 和 ~* 。当同时有多个正则匹配时,按其在配置文件中出现的先后顺序优先匹配,命中则立即停止其他类型匹配;

所有正则匹配均未成功时,返回步骤 2 中暂存的普通前缀匹配(不带参数 ^~ )结果
以上规则简单总结就是优先级从高到低依次为(序号越小优先级越高):

1. location =    # 精准匹配
2. location ^~   # 带参前缀匹配
3. location ~    # 正则匹配(区分大小写)
4. location ~*   # 正则匹配(不区分大小写)
5. location /a   # 普通前缀匹配,优先级低于带参数前缀匹配。
6. location /    # 任何没有匹配成功的,都会匹配这里处理

上述匹配规则可以用以下伪代码表示,加深理解:

function match(uri):
  rv = NULL
  
  if uri in exact_match:
    return exact_match[uri]
  
  if uri in prefix_match:
    if prefix_match[uri] is '^~':
      return prefix_match[uri]
    else:
      rv = prefix_match[uri] // 注意这里没有 return,且这里是最长匹配
   
  if uri in regex_match:
    return regex_match[uri] // 按文件中顺序,找到即返回
  return rv

案例分析
接下来,让我们通过一些实际案例来验证上述规则。

案例 1

server {
    server_name website.com;
    location /doc {
        return 701; # 用这样的方式,可以方便的知道请求到了哪里
    }
    location ~* ^/document$ {
        return 702; 

    }
}
curl -I website.com:8080/document 返回 返回 HTTP/1.1 702

说明:按照上述的规则,显然第二个正则匹配会有更高的优先级

案例 2

server {
    server_name website.com;
    location /document {
        return 701;
    }
    location ~* ^/document$ {
        return 702;
    }
}
curl -I website.com:8080/document 返回 HTTP/1.1 702

说明:第二个匹配了正则表达式,优先级高于第一个普通前缀匹配

例 3

server {
    server_name website.com;
    location ^~ /doc {
        return 701;
    }
    location ~* ^/document$ {
        return 702;
    }
}
curl http://website.com/document 返回 HTTP/1.1 701

说明:第一个前缀匹配 ^~ 命中以后不会再搜寻正则匹配,所以会第一个命中。

案例 4

server {
    server_name website.com;
    location /docu {
        return 701;
    }
    location /doc {
        return 702;
    }
}
curl -I website.com:8080/document 会返回 HTTP/1.1 701

server {
    server_name website.com;
    location /doc {
        return 702;
    }
    location /docu {
        return 701;
    }
}
curl -I website.com:8080/document 依然返回 HTTP/1.1 701

说明:前缀匹配下,返回最长匹配的 location,与 location 所在位置顺序无关

案例 5

server {
    listen 8080;
    server_name website.com;

    location ~ ^/doc[a-z]+ {
        return 701;
    }

    location ~ ^/docu[a-z]+ {
        return 702;
    }
}
curl -I website.com:8080/document 返回 HTTP/1.1 701

把顺序换一下

server {
    listen 8080;
    server_name website.com;

    location ~ ^/docu[a-z]+ {
        return 702;
    }
    
    location ~ ^/doc[a-z]+ {
        return 701;
    }
}
curl -I website.com:8080/document 返回 HTTP/1.1 702

说明:可见正则匹配是使用文件中的顺序,先匹配成功的返回。

案例 6

最后我们对一个官方文档中提到例子做一些补充,来看一个相对较完整的例子,假设我们有如下几个请求等待匹配:

/
/index.html
/documents/document.html
/documents/abc
/images/a.gif
/documents/a.jpg

以下是 location 配置及其匹配情况


location  = / {
    # 只精准匹配 / 的查询.
  [ configuration A ] 
}
# 匹配成功: / 

location / {
    # 匹配任何请求,因为所有请求都是以”/“开始
    # 但是更长字符匹配或者正则表达式匹配会优先匹配
  [ configuration B ] 
}
#匹配成功:/index.html

location /documents {
    # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索/
    # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条/
  [ configuration C ] 
}
# 匹配成功:/documents/document.html
# 匹配成功:/documents/abc

location ~ /documents/ABC {
    # 区分大小写的正则匹配
    # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索/
    # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条/
  [ configuration CC ] 
}

location ^~ /images/ {
    # 匹配任何以 /images/ 开头的地址,匹配符合以后,立即停止往下搜索正则,采用这一条。/
  [ configuration D ] 
}
# 成功匹配:/images/a.gif

location ~* \.(gif|jpg|jpeg)$ {
    # 匹配所有以 .gif、.jpg 或 .jpeg 结尾的请求,不区分大小写
    # 然而,所有请求 /images/ 下的图片会被 [ config D ]  处理,因为 ^~ 到达不了这一条正则/
    [ configuration E ] 
}
# 成功匹配:/documents/a.jpg

location /images/ {
    # 字符匹配到 /images/,继续往下,会发现 ^~ 存在/
  [ configuration F ] 
}

location /images/abc {
    # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在/
    # F与G的放置顺序是没有关系的/
  [ configuration G ] 
}

location ~ /images/abc/ {
    # 只有去掉 [ config D ] 才有效:先最长匹配 [ config G ] 开头的地址,继续往下搜索,匹配到这一条正则,采用/
    [ configuration H ] 
}

其他location配置相关
匹配问号后的参数
请求 URI 中问号后面的参数是不能在 location 中匹配到的,这些参数存储在 $query_string 变量中,可以用 if 来判断。
例如,对于参数中带有单引号 ’ 进行匹配然后重定向到错误页面。

/plus/list.php?tid=19&mid=1124‘
if ( $query_string ~* “.*[;’<>].*” ){
  return 404;
}

location URI结尾带不带 /
关于 URI 尾部的 / 有三点也需要说明一下。第一点与 location 配置有关,其他两点无关。

location 中的字符有没有 / 都没有影响。也就是说 /user/ 和 /user 是一样的。
如果 URI 结构是 https://domain.com/ 的形式,尾部有没有 / 都不会造成重定向。因为浏览器在发起请求的时候,默认加上了 / 。虽然很多浏览器在地址栏里也不会显示 / 。这一点,可以访问baidu验证一下。
如果 URI 的结构是 https://domain.com/some-dir/ 。尾部如果缺少 / 将导致重定向。因为根据约定,URL 尾部的 / 表示目录,没有 / 表示文件。所以访问 /some-dir/ 时,服务器会自动去该目录下找对应的默认文件。如果访问 /some-dir 的话,服务器会先去找 some-dir 文件,找不到的话会将 some-dir 当成目录,重定向到 /some-dir/ ,去该目录下找默认文件。可以去测试一下你的网站是不是这样的。
命名 location
带有 @ 的 location 是用来定义一个命名的 location,这种 location 不参与请求匹配,一般用在内部定向。用法如下:

location / {
    try_files $uri $uri/ @custom
}
location @custom {
    # ...do something
}

上例中,当尝试访问 URI 找不到对应的文件就重定向到我们自定义的命名 location(此处为 custom)。

值得注意的是,命名 location 中不能再嵌套其它的命名 location。

location 实际使用建议
所以实际使用中,个人觉得至少有三个匹配规则定义,如下:

直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。

这里是直接转发给后端应用服务器了,也可以是一个静态首页。第一个必选规则:

location = / {
    proxy_pass http://tomcat:8080/index
}

第二个必选规则是处理静态文件请求,这是 nginx 作为 http 服务器的强项,有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用:

location ^~ /static/ {
    root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
    root /webroot/res/;
}

第三个规则就是通用规则,用来转发动态请求到后端应用服务器,非静态文件请求就默认是动态请求,自己根据实际把握,毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了:

location / {
    proxy_pass http://tomcat:8080/
}

在自定义安装软件的时候,经常需要配置环境变量,下面列举出各种对环境变量的配置方法。

下面所有例子的环境说明如下:

系统:Ubuntu 14.0
用户名:uusama
需要配置MySQL环境变量路径:/home/uusama/mysql/bin

Linux读取环境变量

读取环境变量的方法:+

export命令显示当前系统定义的所有环境变量
echo $PATH命令输出当前的PATH环境变量的值

这两个命令执行的效果如下

uusama@ubuntu:~$ export
declare -x HOME="/home/uusama"
declare -x LANG="en_US.UTF-8"
declare -x LANGUAGE="en_US:"
declare -x LESSCLOSE="/usr/bin/lesspipe %s %s"
declare -x LESSOPEN="| /usr/bin/lesspipe %s"
declare -x LOGNAME="uusama"
declare -x MAIL="/var/mail/uusama"
declare -x PATH="/home/uusama/bin:/home/uusama/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
declare -x SSH_TTY="/dev/pts/0"
declare -x TERM="xterm"
declare -x USER="uusama"

uusama@ubuntu:~$ echo $PATH
/home/uusama/bin:/home/uusama/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

其中PATH变量定义了运行命令的查找路径,以冒号:分割不同的路径,使用export定义的时候可加双引号也可不加。

Linux环境变量配置方法一:export PATH

使用export命令直接修改PATH的值,配置MySQL进入环境变量的方法:

export PATH=/home/uusama/mysql/bin:$PATH


# 或者把PATH放在前面
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

生效时间:立即生效
生效期限:当前终端有效,窗口关闭后无效
生效范围:仅对当前用户有效
配置的环境变量中不要忘了加上原来的配置,即$PATH部分,避免覆盖原来配置

Linux环境变量配置方法二:vim ~/.bashrc

通过修改用户目录下的~/.bashrc文件进行配置:

vim ~/.bashrc

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

生效时间:使用相同的用户打开新的终端时生效,或者手动source ~/.bashrc生效
生效期限:永久有效
生效范围:仅对当前用户有效
如果有后续的环境变量加载文件覆盖了PATH定义,则可能不生效

Linux环境变量配置方法三:vim ~/.bash_profile

和修改~/.bashrc文件类似,也是要在文件最后加上新的路径即可:

vim ~/.bash_profile

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

生效时间:使用相同的用户打开新的终端时生效,或者手动source ~/.bash_profile生效
生效期限:永久有效
生效范围:仅对当前用户有效
如果没有~/.bash_profile文件,则可以编辑~/.profile文件或者新建一个

Linux环境变量配置方法四:vim /etc/bashrc

该方法是修改系统配置,需要管理员权限(如root)或者对该文件的写入权限:

# 如果/etc/bashrc文件不可编辑,需要修改为可编辑
chmod -v u+w /etc/bashrc

vim /etc/bashrc

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

生效时间:新开终端生效,或者手动source /etc/bashrc生效
生效期限:永久有效
生效范围:对所有用户有效

Linux环境变量配置方法五:vim /etc/profile

该方法修改系统配置,需要管理员权限或者对该文件的写入权限,和vim /etc/bashrc类似:

# 如果/etc/profile文件不可编辑,需要修改为可编辑
chmod -v u+w /etc/profile

vim /etc/profile

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

生效时间:新开终端生效,或者手动source /etc/profile生效
生效期限:永久有效
生效范围:对所有用户有效

Linux环境变量配置方法六:vim /etc/environment

该方法是修改系统环境配置文件,需要管理员权限或者对该文件的写入权限:

# 如果/etc/bashrc文件不可编辑,需要修改为可编辑
chmod -v u+w /etc/environment

vim /etc/profile

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

生效时间:新开终端生效,或者手动source /etc/environment生效
生效期限:永久有效
生效范围:对所有用户有效

Linux环境变量加载原理解析

上面列出了环境变量的各种配置方法,那么Linux是如何加载这些配置的呢?是以什么样的顺序加载的呢?

特定的加载顺序会导致相同名称的环境变量定义被覆盖或者不生效。

环境变量的分类
环境变量可以简单的分成用户自定义的环境变量以及系统级别的环境变量。

用户级别环境变量定义文件:~/.bashrc、~/.profile(部分系统为:~/.bash_profile)
系统级别环境变量定义文件:/etc/bashrc、/etc/profile(部分系统为:/etc/bash_profile)、/etc/environment
另外在用户环境变量中,系统会首先读取~/.bash_profile(或者~/.profile)文件,如果没有该文件则读取~/.bash_login,根据这些文件中内容再去读取~/.bashrc。

测试Linux环境变量加载顺序的方法

为了测试各个不同文件的环境变量加载顺序,我们在每个环境变量定义文件中的第一行都定义相同的环境变量UU_ORDER,该变量的值为本身的值连接上当前文件名称。

需要修改的文件如下:

/etc/environment
/etc/profile
/etc/profile.d/test.sh,新建文件,没有文件夹可略过
/etc/bashrc,或者/etc/bash.bashrc
~/.bash_profile,或者~/.profile
~/.bashrc

在每个文件中的第一行都加上下面这句代码,并相应的把冒号后的内容修改为当前文件的绝对文件名。

export UU_ORDER="$UU_ORDER:~/.bash_profile"

修改完之后保存,新开一个窗口,然后echo $UU_ORDER观察变量的值:

uusama@ubuntu:~$ echo $UU_ORDER
$UU_ORDER:/etc/environment:/etc/profile:/etc/bash.bashrc:/etc/profile.d/test.sh:~/.profile:~/.bashrc

可以推测出Linux加载环境变量的顺序如下:

/etc/environment
/etc/profile
/etc/bash.bashrc
/etc/profile.d/test.sh
~/.profile
~/.bashrc

Linux环境变量文件加载详解

由上面的测试可容易得出Linux加载环境变量的顺序如下,:

系统环境变量 -> 用户自定义环境变量
/etc/environment -> /etc/profile -> ~/.profile

打开/etc/profile文件你会发现,该文件的代码中会加载/etc/bash.bashrc文件,然后检查/etc/profile.d/目录下的.sh文件并加载。

# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).

if [ "$PS1" ]; then
  if [ "$BASH" ] && [ "$BASH" != "/bin/sh" ]; then
    # The file bash.bashrc already sets the default PS1.
    # PS1='\h:\w\$ '
    if [ -f /etc/bash.bashrc ]; then
      . /etc/bash.bashrc
    fi
  else
    if [ "`id -u`" -eq 0 ]; then
      PS1='# '
    else
      PS1='$ '
    fi
  fi
fi

if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

其次再打开~/.profile文件,会发现该文件中加载了~/.bashrc文件。

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi
fi

# set PATH so it includes user's private bin directories
PATH="$HOME/bin:$HOME/.local/bin:$PATH"

从~/.profile文件中代码不难发现,/.profile文件只在用户登录的时候读取一次,而/.bashrc会在每次运行Shell脚本的时候读取一次。