Private Repository用git cloneシェルスクリプトの作成(Obsolete)

アクセストークンを用いたgit clone

公開日: 2022-08-05
更新日: 2022-08-25

目的 git clone
OS ubuntu 20.04 LTS Focal Fossa
Requirement アクセストークン取得済み
シェルスクリプト言語 Bash
使用状況 obsolete

REMARKS

  • 現在はGPGキーで保護した.netrc.gpgを用いてgitコマンドを操作しています

Table of Contents

1. Goal: 完成シェルスクリプト

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/bash
## GitHub private repositoryをcloneする関数
## Author: Ryo Nakagami
## Revised: 2022-08-05

## REQUIREMENT
##  GIT_USER, GIT_TOKENなどは別の場所にて変数として保存してある

function usage {
  cat <<EOM
NAME
    $(basename "$0") - Clone a repository into a new directory with User credential info

Syntax
    $(basename "$0") [OPTION] <repository URL>

DESCRIPTION
    This is a wrapper function of git clone
    This allows you to do 'git clone' with your user credential,
    that is, you can git clone private repositories which you can access to.

OPTIONS
  -h, --help
    Display help

  -gl, --gitlab
    you can clone a gitlab repository
EOM

  exit 0
}

function error_message {
    echo 'fatal: something wrong! Check the input'
    exit 1
}

if [[ $1 == '-h' || $1 == '--help' ]]; then
    usage

elif [[ $# == 2 && $2 =~ 'https://gitlab' && ( $1 == '-gl' || $1 == '--gitlab' ) ]]; then
    pass="${GITLAB_USER}:${GITLAB_TOKEN}"
    surfix=$(echo $2 |sed -e 's/^https:\/\//@/g');

elif [[ $# == 1 && $1 =~ 'https://github' ]]; then
    pass="${GIT_USER}:${GIT_TOKEN}"
    surfix=$(echo $1 |sed -e 's/^https:\/\//@/g');

else
    error_message
fi

prefix='https://';
clone_args="$prefix$pass$surfix";
git clone "$clone_args"

GitHub(GitLabも同様ですが)のrepository URLは以下のような構造をしてします:

1
https://github.com/<repository-ownername>/<repository-name>

repositoryがpublicの場合は手元にcloneしたいときは特に問題ないですが, Private Repositoryの場合は以下のような構文を用いる必要があります(ssh接続ではなくアクセストークン経由を想定)

1
git clone https://<user-name>:<access-token>@github.com/<repository-ownername>/<repository-name>

毎回毎回, ちょっと手元で編集してCLI入力するのがめんどくさいので, Repository URLを指定したらユーザー目線ではそのままlocalへgit cloneが実行できるシェルスクリプトを今回作成しました.

BashのVersion

1
2
3
4
5
6
7
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

2. シェルスクリプトとは?

シェルスクリプトとは, シェルに対するコマンドを予めテキストファイルに保存したものです. 複数コマンドを組合せた一連の操作をまとめて実行できます.

あくまで複数のコマンドをまとめて実行するものなので, 複雑なロジックやデータ構造を扱うには適してないことに注意です. 重要なのは,

  • simple & readable
  • 必要最小限の機能が実装されている

この二点を実現することです.

コマンドの基本

コマンドの基本構文に従う形でシェルスクリプトも動作することがsimple & readableにつながります. コマンドの基本構文は基本的には以下4パターンです

1
2
3
4
command
command argument
command option
command option argument

コマンドと, optionや引数のいずれか/両方を用いる利用をする場合は, 半角スペースで区切り, 上の順番で用いることが基本構文となります.

シェルスクリプトの決まりごと

シェルの種別宣言: shebang

シェルスクリプトの1行目はどのシェルを使うのかという宣言から始まります.

1
#!/bin/bash

とあるならばbashを用いると宣言したシェルスクリプトとなります. このようにスクリプト言語のコマンドの絶対パスという形式で記述します. なお, この1行目のことをshebang(シバン)と呼びます.

1
#!/bin/bash -x

と指定すると, シェルスクリプト一行ごとの実行コマンドをTerminal上に表示してくれるので, デバッグ作業のときは重宝されます.

シェルと変数定義

変数を定義するときは variable=STRINGS という構文を用います. 定義した変数を参照したい場合は $variable で文字列として利用することができます.

1
2
3
4
% a=hogehoge
% echo $a; echo ${a}
>>> hogehoge
>>> hogehoge

なお、Pythonみたいに a = hogehoge と入力してしまうと, 「command argument argument」と解釈されてしまうので注意です.

引用符の使い方

シェルスクリプトで文字列を記述する際は, ダブルクォーテーションとシングルクォーテーションの引用符で囲みます. 前者に含まれる変数はその値で置き換えられますが, 後者の場合はその文字列のまま評価されます.

1
2
3
4
5
6
#!/bin/zsh
message=unko
echo $message
echo '$message'
echo "$message"
echo "${message}-unchi"

このときの実行結果は

1
2
3
4
unko
$message
unko
unko-unchi

変数名とその他の文字を続けて記載する場合は, 上の例のように{}で変数名を囲むことでシェルに変数と文字列の区別を命令することができます.

Permissionの設定

シェルスクリプトは, そのままではただのテキストファイルです. 利用するためには, Permissionを設定して実行権限を与える必要があります.

1
% chmod u+x <shell script file>

なお, シェルスクリプトファイルの実行権限を付与したとしても, そのファイルが属するディレクトリに対する実行権限を有していないと結局そのシェルスクリプトは実行できません. ディレクトリに実行権限がないと, その中にあるファイルの中身を参照することができず実行できなくなってしまうことを忘れずに.

PATHの設定

コマンド名だけでシェルスクリプトを実行したい場合, そのシェルスクリプトが存在するディレクトリのPATHをPATH変数に指定すること(=PATHを通す)が必要です.

.zshrc,bash_profileといったファイルで一例として以下のように設定すると,ログイン時やシェル起動時にPATH変数が設定されます.

1
PATH=$PATH:<シェルスクリプトが存在するディレクトリPATH>

複数のPATHをつなぐ場合は:でつなぎます. 実際に上手く登録されているか確認する場合は以下のコマンドで確認できます.

1
% echo $PATH|grep -E "シェルスクリプトが存在するディレクトリPATH"

3. 自作シェルスクリプトの解説

今回作成したシェルスクリプトはgh_cloneという名前で保存しているので, 以下gh_cloneと呼びます.

gh_cloneの主要機能は以下です:

  • GitHubのprivate repositoryのURLを引数に設定すると, 自動的に別箇所に保存されたGitHubアクセストークンとGitHub User名を参照し, git cloneしてくれる
  • Optionに -gl, --gitlab と指定するとGitLabにも対応してくれる
  • Optionに -h, --help と指定するとマニュアルを表示してくれる
  • 入力構文がおかしいときはError Messageを出力してくれる

Syntax

1
gh_clone [option] <Repository URL>
  • この順番は変更不可能です = gh_clone <Repository URL> [option]とはできない
  • optionを指定しない場合は, GitHubのprivate repositoryのgit cloneを試みます

Usage関数の解説

usage関数はいわゆるヘルプメッセージ表示関数です. -h--helpとオプションを指定すると表示されるマニュアルです.

特に引数もオプションもないシェルスクリプトには不必要ですが, もしいずれかがあるならば記載して損はないです. 今回使用したusage関数は以下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function usage {
  cat <<EOM
NAME
    $(basename "$0") - Clone a repository into a new directory with User credential info

Syntax
    $(basename "$0") [OPTION] <repository URL>

DESCRIPTION
    This is a wrapper function of git clone
    This allows you to do 'git clone' with your user credential,
    that is, you can git clone private repositories which you can access to.

OPTIONS
  -h, --help
    Display help

  -l, --gitlab
    you can clone a gitlab repository
EOM

  exit 0
}

メイン部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if [[ $1 == '-h' || $1 == '--help' ]]; then
    usage

elif [[ $# == 2 && $2 =~ 'https://gitlab' && ( $1 == '-gl' || $1 == '--gitlab' ) ]]; then
    pass="${GITLAB_USER}:${GITLAB_TOKEN}"
    surfix=$(echo $2 |sed -e 's/^https:\/\//@/g');

elif [[ $# == 1 && $1 =~ 'https://github' ]]; then
    pass="${GIT_USER}:${GIT_TOKEN}"
    surfix=$(echo $1 |sed -e 's/^https:\/\//@/g');

else
    error_message
fi

prefix='https://';
clone_args="$prefix$pass$surfix";
git clone "$clone_args"

引数としてのURLの接頭部分 ^https:@に変更した後に, その文字列に対してhttps:// + <username> + <access-token>を左から結合 & git cloneしているだけです. 正直なところ -gl, --gitlabとオプションを指定しなくても, URLの文字列にhttps://gitlabという文字列が先頭に含まれているかでどのトークンを参照すべきか分岐はできますが, 一応ユーザーが明示的に意識して入力するほうが良いだろうと判断し, 今回はこの方針に従って条件分岐させています.

条件句内部の =~ 演算子の意味

2つの文字列が与えられた時, 片方がもう片方を含んでいるかの判定をする際に用いる regex operatorが =~です.

1
[[ STR1 =~ STR2 ]]

という条件式があたえられたとき, STR2がSTR1に含まれているならばTrueを返す演算子です.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

STR='GNU/Linux is an operating system'
SUB='Linux'

if [[ "$STR" =~ "$SUB" ]]; then
  echo "It's there."
fi

if [[ "$SUB" =~ "$STR" ]]; then
  echo "It's there in $SUB"
else
  echo "where are you, $STR?"
fi

上記を実行すると以下のような結果が得られます.

1
2
It's there.
where are you, GNU/Linux is an operating system?

4. シェルスクリプト構成要素の解説

メッセージ表示内容: ヒアドキュメント

1
2
3
cat <<EOM
    ...
EOM

EOMで囲まれた箇所がTerminal上でヘルプメッセージとして表示されます. EOMであること自体には意味はなく, 同じ文字列で囲まれているかが重要です.

cat <<EOMはヒアドキュメントと分類されるリダイレクトのことで一般化すると

1
% command <<STRINGS

と表現されます. 基本的には echo '文章'と同じですが, 複数行に渡る長文や長文の中でシェル変数を展開したい場合に重宝されます. STRINGS 部分は任意の文字列で大丈夫です.

REMARKS

  • ヒアドキュメントは標準入力として扱われ, 文字列リテラルではありません

basenameコマンド: パス名からファイル名を取得

basenameは, ディレクトリ名とファイル名を含むパス名から, ディレクトリ部分を除き, ファイル名だけを取得 & 標準出力に出力するコマンドです.

対話型シェルを起動している時, $0変数には現在利用しているシェルのPATHが設定されています. echoでPATHを表示, basenameでファイル名の取得を試みると以下のような結果を得ます.

1
2
3
% echo $0 && basename $0
/usr/bin/zsh
zsh

コマンド置換: 標準出力結果を文字列へ

コマンド置換を利用すると, コマンドの標準出力結果を文字列値として利用できるようになります. コマンド置換のSyntaxは

1
$(command)

例として、以下の出力結果を比べてみます.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
### 一般的なコマンド置換
cat <<EOM
    NAME $(basename "$0")
EOM

cat <<EOM
    NAME "basename $0"
EOM

cat <<EOM
    NAME $basename $0
EOM

### バッククォーテーションで囲む
cat <<EOM
    NAME `basename $0`
EOM

この時の結果は,

1
2
3
4
    NAME zsh
    NAME "basename /usr/bin/zsh"
    NAME  /usr/bin/zsh
    NAME zsh

コマンドのFULL PATHからPermisision設定を確認したい場合は

1
% ls -l $(which gh_clone)

REMARKS

  • バッククォーテーションで囲んでもコマンド置換は実施可能ですが, 読みづらさが増すので利用は非推奨です

位置パラメータ

位置パラメータとは, スクリプトが呼び出された際のコマンドライン引数を保持するための特別な組込み変数のことです. シェルスクリプトを実行するときのコマンドラインに引数を渡すと, シェルはそれらの値を位置パラメータ(Positional Parameters)に設定します.

変数 機能
$0 スクリプト名
$1 ~ $9 引数、1番目の引数を$1, 2番目の引数を$2でアクセスする
$# スクリプトに与えた引数の数
$* 全部の引数をまとめて1つとして処理
$@ 全部の引数を個別として処理
$? 直前実行したコマンドの終了値(0は成功、1は失敗)
$$ このシェルスクリプトのプロセスID
$! 最後に実行したバックグラウンドプロセスID

$*$@は違いは分かりづらいですが, 引数リストをそっくりそのまま別のスクリプトや関数に渡す場合, $* は 1つの文字列として解釈され,$@ はそれぞれ別々のn個の文字列として解釈されるという違いがあります.

REMARKS

  • bashで記載されたシェルスクリプトにて, $0 はスクリプト内でグローバル変数であるが, それ以外は関数内でのローカルな変数となります.

ただし, この関係性は zshの場合は異なります. 上記シェルスクリプトのshebangを#!/bin/zshに変更し, helpを表示すると確認できます)

exitコマンド

Syntax

1
exit [n]

機能

  • シェルを終了するコマンド (= exitを使うことにより任意の位置で実行を終了させることができる)
  • システムに返す終了状態を指定することができます
  • 0が正常終了で, 1が異常終了という設定が一般的です

直前のコマンドの終了ステータスの取得

1
2
3
gh_clone -h
echo $? 
>>> 0

Appendix

typeコマンドでコマンドの正体を調べる

ユーザーが普段Linuxで使用するコマンドは大きく外部コマンド, 内部コマンド, エイリアスに分類されます.

  • 内部コマンド: シェル本体がもっているコマンド, a shell builtin
  • 外部コマンド: 実行ファイルとして個別に保存されているコマンド, 自作シェルスクリプトもここに分類される
  • エイリアス: コマンドやオプションや引数を組合せて作成したコマンドを別名で保存しているもの

typeコマンド

コマンド名を見ただけでは, それがエイリアスなのか内部コマンドなのか外部コマンドなのか識別することは難しいです. そこで利用するのが typeコマンドです.

例として以下,

1
2
3
4
5
6
7
8
% type cd
cd is a shell builtin
% type awk 
awk is /usr/bin/awk
% type lc
lc is an alias for ls -F --color=auto --group-directories-first
% type for
for is a reserved word

References

関連ポスト

参考書籍

オンラインマテリアル



Share Buttons
Share on:

Feature Tags
Leave a Comment
(注意:GitHub Accountが必要となります)