文章目录
- 本文的目的是提升linux shell脚本的功力,以及熟悉spark-submit提交的具体流程
- spark-sumbit*
- 第一段
- 背景知识
- 综合案例
- 解读
- 第二段
- 背景知识
- 解读
- 第三段
- 背景知识
- 解读
- 总结语
本文的目的是提升linux shell脚本的功力,以及熟悉spark-submit提交的具体流程
spark-sumbit*
1
2
3
4
5
6
7
8
9
10
11
12#!/usr/bin/env bash if [ -z "${SPARK_HOME}" ]; then source "$(dirname "$0")"/find-spark-home fi # disable randomized hash for string in Python 3.3+ export PYTHONHASHSEED=0 exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"
第一段
1
2
3
4if [ -z "${SPARK_HOME}" ]; then source "$(dirname "$0")"/find-spark-home fi
背景知识
-
双引号
"${SPARK_HOME}" 与 ${SPARK_HOME} 这样写是等效的,均代表获取环境变量中的SPARK_HOME所引用的值
在shell中 “$USER” 与 $USER 其代表的值是一样的。 加不加并不会记录到变量中,也不会添加到字符串中,其代表的一个根本的含义就是 定义 变量的意思。默认情况下,在shell编程中,不带双引号的都会被当作字符串来处理。这个惯例比较特殊。反正与一般意义上的高级编程语言不太一致。(读者可以自己揣摩一下单引号会得出什么样的结论)
复制代码1
2
3
4
5
6
7
8#!/bin/bash if [ $USER = "$USER" ];then echo "eq" # 执行eq else echo "neq" fi
-
if(空格)[(空格)-[a-z](空格)(string)(空格)];then 语法
这个是常见的shell 字符串条件判断的格式,-z代表不存在,请注意空格是必填的,这个是跟处理shell脚本的编译器设置的语法解析器有关,或者说内置的正则表达式就是这么获取条件匹配的
在方括号内退出码为0(exit 0即正常退出)则执行then后面的语句,否则执行其他分支复制代码1
2
3
4homewell:/home/hadoop/shareh$ cat /etc/passwd | grep abc homewell:/home/hadoop/shareh$ echo $? 1
比较其原型 是test命令
-
source命令(直接copy命令)
有人说是点(.)命令,也就是执行目标文件中的命令,但是source 不会执行生成子shell(概念要理清,这个子shell代表这创建一个新的进程被父进程管理环境变量)
如果读者学过C++或者C,都会接触宏(#define)关键字,代表者代码在编译的时候直接把代码copy到引用了宏定义的代码段中,或者类似于C++中的内联函数,都是代码的直接copy.可以看 综合案例
因此可以使用另一个脚本中暴露(export)的变量,因为相当于把另一脚本中的代码,直接copy到当前脚本中
参考1
参考2 -
dirname 命令
获取指定虚拟目录的父目录
复制代码1
2
3
4
5
6
7homewell:/home/hadoop/shareh$ dirname /home/hadoop/shareh/ /home/hadoop homewell:/home/hadoop/shareh$ dirname /home/hadoop/shareh/abc abc/ abcd/ abc.sh homewell:/home/hadoop/shareh$ dirname /home/hadoop/shareh/abc.sh /home/hadoop/shareh
-
位置参数
$0是调用程序的时候第一个字符串,通常与程序名一致,往往有些博客简单地把它理解成程序名,这样理解是很受伤的,很容易误伤,针对这种情况。希望读者能区分不同场景来理解(查看本案例)
$1是第一个参数,$2是第二个参数
5.案例
复制代码1
2
3
4
5
6
7#!/bin/bash echo "$0:""$0" echo "$1:""$1" # 超过10个参数的用{}包裹起来,否则 $10 == "$1" + "0" echo "第十个参数""${10}"
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35# 第一 全路径方式 homewell:~$ /home/homewell/shell1/testdoller.sh 23 $0:/home/homewell/shell1/testdoller.sh $1:23 # 全局变量方式(同上是一致的) homewell:~/shell1$ export SHELLTEST_HOME="/home/homewell/shell1" homewell:~/shell1$ export PATH="$SHELLTEST_HOME:$PATH" homewell:~/shell1$ testdoller.sh 1235 $0:/home/homewell/shell1/testdoller.sh $1:1235 # 第二种 通过相对路径1 homewell:~$ shell1/testdoller.sh 124 $0:shell1/testdoller.sh $1:124 # 第二种 通过相对路径2 homewell:~$ ./shell1/testdoller.sh 124 $0:./shell1/testdoller.sh $1:124 # 第三种 直接以./方式执行 homewell:~$ cd shell1/ homewell:~/shell1$ ./testdoller.sh 125 $0:./testdoller.sh $1:125 # 第四种 通过sh 命令执行 homewell:~/shell1$ sh testdoller.sh 126 $0:testdoller.sh $1:126
扩展内容 其他内置的跟$有关的位置参数
综合案例
1
2
3-rwxr-xr-x 1 zhangll zhangll 184 10月 2 21:14 pid2.sh* -rwxrwxrwx 1 zhangll zhangll 1292 10月 2 21:40 pid.sh*
pid.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41#!/bin/bash 表示当前shell echo "pid.sh当前shell pid进程($$):$$" echo "pid.sh当前shell最近一个后台进程pid($!):" "$!" echo "pid.sh前面一个命令的退出码 ($?) : $?" # 执行当前的目录路径下的pid2.sh echo "-------------./pid2.sh--------------" ./pid2.sh echo "pid.sh当前进程打印 pid2中的pid2暴露的变量($PID2): $PID2" echo "-------------查看(子进程)的一些特性------------" # 向外暴露a变量,在父进程中无法查看,只有在子shell中能看 export a=1 echo "pid.sh当前shell显示a 变量($a):"$a (export b=2; echo "子进程查看父进程暴露的(a):""$a";echo "子进程暴露的变量($b):""$b";echo "子进程打印的进程($$):""$$";echo "子进程($BASHPID):$BASHPID") echo "pid.sh 在 (子进程之后)当前shell最近一个后台进程pid2($!):" "$!" echo "pid.sh当前shell显示子进程暴露的b变量($b) : $b" echo "------------(./pid2.sh &)------------" ./pid2.sh & echo "pid.sh 在 (./pid2.sh &)最近一个后台进程pid2($!):" "$!" echo "pid.sh当前进程打印 pid2中的pid2暴露的变量($PID2): $PID2" echo "-----------source pid2.sh -----------" source ./pid2.sh echo "pid.sh source pid2.sh 之后当前进程打印 pid2中的pid2暴露的变量($PID2): $PID2" exit 0
pid2.sh
1
2
3
4
5
6
7#!/bin/bash echo "######pid2.sh 打印的 ($$):$$" echo "######pid2.sh 打印的 ($BASHPID):$BASHPID" echo "######pid2.sh 打印的最近一个后台进程 ($!):$!" export PID2=30
执行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36pid.sh当前shell pid进程($$):9553 pid.sh当前shell最近一个后台进程pid($!): pid.sh前面一个命令的退出码 ($?) : 0 -------------./pid2.sh-------------- ######pid2.sh 打印的 ($$):9554 ######pid2.sh 打印的 ($BASHPID):9554 ######pid2.sh 打印的最近一个后台进程 ($!): pid.sh当前进程打印 pid2中的pid2暴露的变量($PID2): -------------查看(子进程)的一些特性------------ pid.sh当前shell显示a 变量($a):1 子进程查看父进程暴露的(a):1 子进程暴露的变量($b):2 子进程打印的进程($$):9553 子进程($BASHPID):9555 pid.sh 在 (子进程之后)当前shell最近一个后台进程pid2($!): pid.sh当前shell显示子进程暴露的b变量($b) : ------------(./pid2.sh &)------------ ######pid2.sh 打印的 ($$):9556 ######pid2.sh 打印的 ($BASHPID):9556 ######pid2.sh 打印的最近一个后台进程 ($!): pid.sh 在 (./pid2.sh &)最近一个后台进程pid2($!): 9556 pid.sh当前进程打印 pid2中的pid2暴露的变量($PID2): -----------source pid2.sh ----------- ######pid2.sh 打印的 ($$):9553 ######pid2.sh 打印的 ($BASHPID):9553 ######pid2.sh 打印的最近一个后台进程 ($!):9556 pid.sh source pid2.sh 之后当前进程打印 pid2中的pid2暴露的变量($PID2): 30
可以发现
- $! 代表当前shell进程空间最近一个执行的后台进程的id,并不会获取父进程空间的最近一次后台进程pid
后台进程与子进程的区别 - ()括号包裹的虽然是开启了一个新的空间,但是其进程id与父亲的一致,但是在其内暴露(export)的变量,父进程无法获取
- $$ 并非代表当前shell的pid,
解读
1
2
3不管以./spark-submit 还是 直接执行spark-submit,当不存在SPARK_HOME环境变量的时候,就执行当前目录(spark-submit所在目录)中的find-spark-home命令 很显然find-spark-home 要做的工作肯定是设置一个 SPARK_HOME 环境变量用来给后期使用
第二段
1
2
3# disable randomized hash for string in Python 3.3+ export PYTHONHASHSEED=0
背景知识
-
export 暴露/导出
该关键词在nodejs/js/c/c++中会经常出现,代表这给调用该脚本的环境(脚本/shell环境)暴露一个变量,这个变量将会在当前进程空间中使用,包括子进程空间,但是不会影响父进程空间的变量
解读
很显然暴露了一个PYTHONHASHSEED (python hash seed)
这个是设置一个python随机
中的seed值,当改值为0的时候,代表着关闭随机hash种子,意味着对相同字符串多次使用hash函数,得到的是相同的值,这里可能考虑到pyspark上会调用hash值产生不必要的麻烦,比如spark中的group by 算子,由于可能数据在不同节点上,因此不同节点上会启动不同的python环境(可以理解成python session),python3.2.3之后就默认开启python环境的hash值,这意味着不同环境下的相同字符串,会默认在字符串前面添加一个盐值,防止DOS拒绝服务攻击手段,防止链表太长,降低性能。然后在group by 的相同字符串可能会在不同机器上输出不同 内容,因此为了能够保证数据一致性,需要关闭这个值
地址
第三段
1
2exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"
背景知识
-
exec 命令 参数
代表当前命令与参数 直接覆盖当前shell内容,这个是最暴力的宏替换,不过会暴露当前的用户变量(局部变量)与全局变量
案例见 Linux shell 整理之 复合命令行篇(四)
-
exec 永久重定向操作
案例见 Linux shell 整理之 复合命令行篇(四)
-
双引号
同第一段 1)
解读
因此第三段的意思就是使用spark_home/bin/spark-class 并且传递两个参数
第一个是 org.apache.spark.deploy.SparkSubmit
第二个是 " @ " 代 表 当 前 s h e l l 执 行 所 窜 入 的 参 数 个 体 集 合 的 列 表 , 根 据 实 际 情 况 当 然 可 以 用 " @" 代表当前shell 执行所窜入的参数个体集合的列表,根据实际情况当然可以用 " @"代表当前shell执行所窜入的参数个体集合的列表,根据实际情况当然可以用""来代替。$@ 代表着把输入参数作为多个个体存在,而 $ 可以作为一个单独的个体存在
总结语
纸上得来终觉浅,绝知此事要躬行。简简单单3句话,其涵盖的内容,不是一两句话能够得出来的。当你用心去体会的时候,你会发现,原来一切都这么简单明白
最后
以上就是重要钢铁侠最近收集整理的关于spark-submit 到底做了什么的全部内容,更多相关spark-submit内容请搜索靠谱客的其他文章。
发表评论 取消回复