Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bash shell pre-commit eslint prettier #49

Open
willson-wang opened this issue Dec 2, 2018 · 0 comments
Open

bash shell pre-commit eslint prettier #49

willson-wang opened this issue Dec 2, 2018 · 0 comments
Labels
shell bash shell

Comments

@willson-wang
Copy link
Owner

willson-wang commented Dec 2, 2018

You can use Prettier and Eslint with a pre-commit tool. This can re-format your files that are marked as "staged" via git add before you commit.

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言;Shell 脚本(shell script),是一种为 shell 编写的脚本程序,业界所说的 shell 通常都是指 shell 脚本;

shell环境,Shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。Linux 的 Shell 种类众多,常见的有

  1. Bourne Shell(/usr/bin/sh或/bin/sh)
  2. Bourne Again Shell(/bin/bash)
  3. C Shell(/usr/bin/csh)
  4. K Shell(/usr/bin/ksh)
  5. Shell for Root(/sbin/sh)

这次要学习的是Bash,也就是 Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell;在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash

shell语法

#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序,如#!/bin/sh or #!/bin/bash or #!/bin/node

1 运行 Shell 脚本有两种方法

第一种是作为可执行程序,需要注意的是,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找

chmod +x ./test.sh  #使脚本具有执行权限
./test.sh  #执行脚本

第二种是作为解释器参数
/bin/sh test.sh
/bin/php test.php

2 shell变量

定义变量时,变量名不加美元符号,变量名和等号之间不能有空格,变量名跟js的变量名一样,不能以数字开头等;name="jack"

使用变量时,需要在变量名前加$,变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界;变量能过被重新赋值;

name="jack" 
echo $name
echo ${name}

只读变量,在变量名前加readonly关键字

name="rose"
readonly name

删除变量,使用unset操作符,不能删除只读变量

name="rose"
unset name
echo $name // 为空

3 shell 字符串

字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。

单引跟双引的区别:单引号字符串中的变量是无效的,双引号中才可以;双引号里可以出现转义字符,单引号不行;建议使用双引

获取字符串的长度${#name}
截取字符串${#name:1:3}

4 shell 数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小,通过下标来取值,下标从0开始

定义数组:数组名=(值1 值2 ... 值n)
读取数组:${数组名[下标]},使用 @ 符号可以获取数组中的所有元素
获取数组的长度:length=${#array_name[@]} or length=${#array_name[*]}

arr=(1 3 5 7)
echo ${arr[1]} ${#arr[@]}

5 注释

单行注释:#
多行注释::<<EOF EOF or :<<! !

6 shell传递参数

我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……

获取第n个参数$n
获取参数的个数 $#
获取所有参数的字符串 $*
获取最后命令的退出状态 $? 0表示没有错误,其它表示有错误

$* 与 $@ 区别,只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)

echo $1 $2 $3 $# $* $?

7 shell运算符

算数运算符 + - * / = == != 针对的是数字
关系运算符 -eq(等于) -ne(不等) -gt(大于) -lt(小于) -ge(大于等于) -le(大于小于) 只支持数字,不支持字符串,除非字符串的值是数字
布尔运算符 ! -o -a
逻辑运算符 && ||
字符串运算符 = != -z -n str

文件测试运算符

操作符 说明 举例
-b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -c $file ] 返回 false。
-d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。
-p file 检测文件是否是有名管道,如果是,则返回 true。 [ -p $file ] 返回 false。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。 [ -u $file ] 返回 false。
-r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
-w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。

注意使用到运算符的地方,必须需要注意的是条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]

a=10
b=5
echo `expr $a + $b`
if [ $a == $b ]
then
   echo "a 等于 b"
fi
if [ $a != $b ]
then
   echo "a 不等于 b"
fi

if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi

str="i am fine"
str1="i am fine"

if [ -z "$str" ]
then
    echo '为0'
else
    echo '不为0'
fi 

if [ "$str1" ]
then
    echo '不为空'
else
    echo '为空'
fi 

file="./test.sh"
file1="./src"

if [ -x $file ]
then
   echo "文件可执行"
else
   echo "文件不可执行"
fi

if [ -s $file ]
then
   echo "文件不为空"
else
   echo "文件为空"
fi

if [ -d $file1 ]
then
   echo "文件是目录"
else
   echo "文件不是目录"
fi

if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi

8 echo

echo 重定向到文件 也就是把内容输出到某个位置
echo "it a test" > myfile.txt

echo 显示普通字符串的时候可以省略引号

9 test命令

Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试

test命令其实就是运算符中的[]

a=5
b=10
// 二者等价
if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi

if test $a -eq $b 
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi

// 二者等价
if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi

if test -e $file
then
    echo "文件存在"
else
   echo "文件不存在"
fi

10 流程语句

if else语句跟普通的js内的流程语句还是有区别的,如else分支没有语句执行,就不要写这个else;if后面要跟then,需要使用fi来结尾

if condition
then
    command1 
    command2
    ...
    commandN 
fi

if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi

for循环

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

while

let 命令,它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量

while condition
do
    command
done

int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done

break 与continue关键字

for loop in 1 2 3 4 5
do
    if test $loop -gt "3"
    then 
        echo '循环break'
        break
    else
        echo "The value is: $loop"
    fi
done

for loop in 1 2 3 4 5
do
    if test $loop -eq "3"
    then 
        echo '循环continue'
        continue
    else
        echo "The value is: $loop"
    fi
done

11 输入输出重定向

命令 说明
command > file 将输出重定向到 file。
command < file 将输入重定向到 file。
command >> file 将输出以追加的方式重定向到 file。
n > file 将文件描述符为 n 的文件重定向到 file。
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m 将输出文件 m 和 n 合并。
n <& m 将输入文件 m 和 n 合并。
<< tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入。

需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)

如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null
command > /dev/null

echo '输出重定向' > redict.txt
echo '输出重定向覆盖' > redict.txt
echo '输出重定向追加' >> redict.txt

实例

在shell脚本内直接执行npm script内的命令

#!/bin/sh
# To enable this hook, rename this file to "pre-commit".

echo 'hello wolrd'

npm run prettier && npm run lint:fix && npm run lint

git add .

pre-commit钩子内进行eslint检查与代码格式化,实现方案1

#!/bin/sh

# To enable this hook, rename this file to "pre-commit".

echo "pre-commit"

# git rev-parse --show-toplevel显示顶级目录的绝对路径

ESLINT="$(git rev-parse --show-toplevel)/node_modules/.bin/eslint"
PRETTIER="$(git rev-parse --show-toplevel)/node_modules/.bin/prettier"

STAGE_FILES_JS=$(git diff --cached --name-only --diff-filter=ACM -- '*.js')
STAGE_FILES_VUE=$(git diff --cached --name-only --diff-filter=ACM -- '*.vue')

if test ${#STAGE_FILES_JS} -gt 0
then 
	echo '开始eslint检查js'

	# 第一种检查方式
	# which eslint &> /dev/null
	# if [[ "$?" == 1 ]]; then
	# 	echo '没有安装eslint'
	# 	exit 1
	# fi

	# which prettier &> /dev/null
	# if [[ "$?" == 1 ]]; then
	# 	echo '没有安装prettier'
	# 	exit 1
	# fi

	# 第二种检查方式
	# if [[ ! -x "$ESLINT" ]]; then
 #      echo "\t\033[41mPlease install ESlint\033[0m (npm i --save --save-exact --dev eslint)"
 #      exit 1
 #    fi

 	# 跟第一种检查方式一样,只不过使用相对路径
 	which ./node_modules/.bin/eslint &> /dev/null
	if [[ "$?" == 1 ]]; then
		echo '没有安装eslint'
		exit 1
	fi 

    if [[ ! -x "$PRETTIER" ]]; then
       echo "\t\033[41mPlease install prettier\033[0m (npm i --save --save-exact --dev prettier)"
       exit 1
    fi


	PASS1=true

	for FILE1 in $STAGE_FILES_JS
	do
		# 如果是本地安装的eslint则需要使用变量,且需要使用"$ESLINT" "$FILE"而不是eslint "$FILE"
		"$PRETTIER" "$FILE1" --write --parser flow
		./node_modules/.bin/eslint "$FILE1" 
		if [[ "$?" == 1 ]]; then
		PASS1=false
	fi
  done

  if ! $PASS1; then
	echo 'eslint js未通过'
	exit 1
  else 
	echo 'eslint js通过'
  fi

else
	echo '暂存区没有需要检查的js文件'
fi

if test ${#STAGE_FILES_VUE} -gt 0
then 
	echo '开始eslint检查vue'

	PASS2=true

	for FILE2 in $STAGE_FILES_VUE
	do
		# 如果是本地安装的eslint则需要使用变量,且需要使用"$ESLINT" "$FILE"而不是eslint "$FILE"
		"$PRETTIER" "$FILE2" --write --parser vue
		# "$ESLINT" "$FILE2" 
		./node_modules/.bin/eslint "$FILE2" 
		if [[ "$?" == 1 ]]; then
		PASS2=false
	fi
  done

  if ! $PASS2; then
	echo 'eslint vue未通过'
	exit 1
  else 
	echo 'eslint vue通过'
  fi

else
	echo '暂存区没有需要检查的vue文件'
fi

exit 0

pre-commit钩子内进行eslint检查与代码格式化,实现方案2

#!/bin/bash

# pre-commit

echo 'pre-commit start'

# 检查是否安装eslint,注意路径,根据自己的实际项目路径填写
eslint="../../node_modules/.bin/eslint"
prettier="../../node_modules/.bin/prettier"
echo $(git rev-parse --show-prefix)
if test -x $eslint && test -x $prettier
then
  echo "eslint及prettier存在"
elif test -x $eslint
then
  echo "prettier依赖不存在请进行安装"
  exit 1
else
  echo "eslint依赖不存在请进行安装"
  exit 1
fi

# 获取当前git仓库内暂存区文件

STATGE_FILES=$(git diff --cached --name-only --diff-filter=ACM '*.js' '*.vue')
FILE_VUE_TYPE="vue"

if test ${#STATGE_FILES} -gt 0
then 
  echo "当前暂存区内有${#STATGE_FILES}个js or vue文件"

  # 遍历暂存区文件,使用eslint检查及prettier格式化代码
  PAAS=true
  for file in $STATGE_FILES
    do
      # 通过${file##*.}来获取文件后缀,判断是否是js文件还是vue文件
      if test ${file##*.} = $FILE_VUE_TYPE
      then
        $prettier $file --parser vue --write
      else
        $prettier $file --parser flow --write
      fi

      # eslint检查
      $eslint $file --color

      # 判断eslint执行的结果如果最后执行的命令返回不是0表示eslint检查不通过
      if test $? -ne 0
      then
        PAAS=false
      fi
    done

  if ! $PAAS
  then
    echo "eslint不通过"
    exit 1
  else 
    echo "eslint通过"
  fi

else 
  echo "当前暂存区内有没js及vue文件"
fi

exit 0

参考链接:
https://gist.github.com/linhmtran168/2286aeafe747e78f53bf
https://www.tutorialspoint.com/unix/shell_scripting.htm

@willson-wang willson-wang changed the title bash shell pre-commit bash shell pre-commit eslint prettier Dec 7, 2018
@willson-wang willson-wang added the shell bash shell label Dec 7, 2018
@willson-wang willson-wang changed the title bash shell pre-commit eslint prettier shell bash pre-commit eslint prettier Dec 8, 2018
@willson-wang willson-wang changed the title shell bash pre-commit eslint prettier pre-commit hook eslint prettier Dec 8, 2018
@willson-wang willson-wang changed the title pre-commit hook eslint prettier Pre-commit Hook · Prettier · Eslint Dec 8, 2018
@willson-wang willson-wang changed the title Pre-commit Hook · Prettier · Eslint bash shell pre-commit eslint prettier Dec 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
shell bash shell
Projects
None yet
Development

No branches or pull requests

1 participant