28
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

シェルスクリプト作成Tips sh

Last updated at Posted at 2020-04-16

zshを使ってます。
まだ途中だけどとりあえず投下して追記していきたい。。。

##参考
【初心者向け】シェルスクリプトの作り方と実行方法
スクリプト中で実行しているコマンドを表示する
実用的なシェルスクリプト
シェルスクリプト
【簡単】シェルスクリプトでテキストを改行する方法
bashのif文でワイルドカード・正規表現を用いて条件判断をさせる | 俺的備忘録 〜なんかいろいろ〜
bashのsetコマンドで覚えておきたい使い方9個 | 俺的備忘録 〜なんかいろいろ〜
シェルスクリプトで複数行のコメントアウト
Shell 特殊変数 - Qiita
Bashの便利な構文だがよく忘れてしまうものの備忘録 - Qiita

Tips

#!/usr/bin/zsh
これはスクリプトの一行目に記述する定型文。
この一行目で、実行時どのシェルでスクリプトを実行するかが決まる。
(bashやzshの独自機能を使わないのであれば#!/usr/shでいいっぽい)

zsh -x test.sh
-x オプションを付けてシェル実行(例としてtest.shを実行)すると
shファイル内に記述されたコマンドも含めて表示する(デバッグ用途?)。

:
if文分岐内容などで何もしない処理を表す。
実際のコードで「何もしないから何も書かない」でいるとエラーになるので
エラー回避のための記述になる。

コメントアウト

1行
echo hoge
# echo "ここは実行されない"
echo piyo

複数行の場合は << 任意の文字列 で複数行を括る。
コメントアウト終了部分には << は記述不要

複数行

echo hoge
<< COMMENT
echo "ここは実行されない"
echo "実行されないんですよ!"
COMMENT
例外
#!/bin/bash シェルスクリプト名.sh

シェルスクリプト1行目のコメントアウトは
bash(を起動させるため)のパス指定として機能している。(ただのコメントアウトではない)

ここの記述がおかしいと(パスが違うので)実行権つけてもスクリプト名だけで実行ができなかったり
そもそもシェル内で使用できる記述形式が変化したり (結果エラーwww) する。

スクリプト名取得

echo "$0"  #シェル名のフルパス出力
echo "$(basename $0)"  #シェル名だけ出力

# /home/huga/hoge.sh
# hoge.sh

引数

シェルスクリプトや関数等に渡す値。
任意の値をスクリプトや関数に引き継がせて処理を進めたいときなどに使用。

配置
# スクリプト名.sh 引数

sample.sh arg
引数を連結して表示
echo "$*"

# 変数に入れてから表示させる
list=($*)
echo "${list[*]}"
引数を渡して実行した関数を変数に格納
#!/bin/bash array2.sh

[[ $# -eq 0 ]] && echo "nothing" | command return

function calc_one(){
  sum=0
  for c in "$@"; do sum=$(($sum + $c)); done
  echo "$sum"
}

result=`calc_one $*`
echo "$result"
実行例
$ array2.sh 1 2 3
6
引数の内容表示種別
echo "$#"  # 引数の数
echo "$1"  # 1つ目の引数の内容
echo "$*"  # 全引数の内容
echo "$@"  # 全引数の内容
実行例
$ sample.sh a b c d e

5
a
a b c d e
a b c d e

#変数
宣言時は
fff_fff=""のように記述(=間のスペースは空けない)
呼出し時は$つけて
$fff_fff

変数にコマンド内容を設定する場合は
cmd=`cd ~/$HOME`のようにバッククォートでコマンド部分を挟んで記述

ファイルのパスを取得する(相対/絶対)

相対パスを取得
#dirname ${0}

path=`dirname ${0}`
echo $path
絶対パスを取得
#cd $(dirname ${0}) && pwd

filepath=`cd $(dirname ${0}) && pwd`
echo $filepath

四則演算

記述サンプル
echo $((1 + 2))	# 足し算
echo $((3 - 4))	# 引き算
echo $((5 * 6))	# かけ算
echo $((8 / 7))	# 割り算(割り切れない場合は小数以下が消える)
echo $((10 % 9))	# 剰余
echo $((11 ** 12))	# 階乗
符号間のスペースは空けなくても良い
echo $((114+514)) 

数字の判定

-gt -ge   -eq   -le  -lt
 >   >=    =     <=   <
-eq # =  equal 等しい
-gt # >  greater than
-ge # >= greater than or equal
-lt # <  less than
-le # <= less than or equal

#関数

#記述形式
testKansu(){
  echo "処理内容"
}

#呼び出し
testKansu

#コマンドあれこれ
###read

#入力を受け付ける
read HENSU
echo $HENSU

#文字表示と組み合わせる場合
read -p "何か入力してください" ANSWER
echo $ANSWER

ecco -n "何か入力してください"; read ANSWER
[[ -n $ANSWER ]] && echo $ANSWER #入力がない場合、実行されない
関数に渡す
funcOne(){
  echo "おはよう! "$HIKISU"ぎ君"
  echo -e "さよなら! ${HIKISU}ぎ君\nそいつは $1ぎだ!"
}

read -p "何か入力してください" HIKISU
funcOne $HIKISU #入力内容を引数にして関数に投げたりできる

コマンドを繋げて実行(セミコロン アンパサント x2 パイプ x2)

ワンライナーでの「if・else」文記述などの際に
;  複数のコマンドを1行で記述して繋げて実行

&& 先のコマンドが真で完了(true 成功)した際に次のコマンドを実行

|| 先のコマンドが偽で終了(false 失敗)した際に次のコマンドを実行
サンプル
# ; セミコロン前後のスペースは割と曖昧でも実行できる
pwd;ls
pwd; ls
pwd ;ls
pwd ; ls
pwd    ; ls
pwd ;         ls

# ; 何個でもぉ 連結可能
echo;pwd;echo;uname;hostname

# && 先のコマンドが成功すれば続けて後のコマンドを実行
mkdir test_01 && cd $_

# || 簡単なtestコマンドなら1行で書ける
a=1;test $a -eq 2 || echo no
;
echo 'Hoge!';pwd;ls -l

# 文字列括りにダブルクォーテーション(")を使うと
# 含まれる文字列によっては実行結果がおかしくなるので注意

\で、改行を無視して1行のコマンドとして実行可能
echo "Hoge!, \
tororo ms\
--nkb."

# Hoge!, tororo ms--nkb.

リダイレクト

ファイル内容を初期化

「:」で上書きして内容を空にする
: > test.txt

標準出力に表示させずにコマンド実行 /dev/null

コマンドは実行させたいが、余計な結果出力を省きたい場合に使用

エラーも含めてコマンド結果を全て表示しない
&>/dev/null
ls &>/dev/null
# ls >/dev/null 2>&1
エラーは表示
>/dev/null
ls >/dev/null
# ls 1>/dev/null

その他

# 追記 >>
echo 'hoge' >> test.txt

# 強制上書き >| or >!
echo 'important' >| test.txt
echo 'important' >! test.txt

# 強制追記 >>| or >>!
echo 'important add' >>| test.txt
echo 'important add' >>! test.txt

※ 強制上書きは危険なので注意
※ シェルによっては >! は使えなかったり

#if文記述(testコマンド)
testコマンドで条件判定できる。[] で囲むとtestコマンドと同じ効果になる。
if文は基本的に [] を利用して条件式を記述する。

if [] = test
if [ "$1" == "piyo" ] = test "$1" == "piyo"

通常形式
if [ "$1" == "piyo" ]; then
  echo "TRUE"
elif [ "$url" == "katu" ]&&[ "$url" == "dearu" ]; then
  echo "AND条件"
elif [ "$url" == "mosikuha" ] || [ "$url" == "matawa" ]; then
  echo "OR条件"
else
  :
fi
ワンライナー形式
#値(場所)が存在する
[ -e ~/nanyanen/honma ] && echo "aruyo"
#値(場所)が存在しない
[ ! -e ~/nandeyanen/ahoka ] && echo "naiyo--"
#値がある(空でない)1
[ -n $nokara ] && echo $ataiari
#値が空である
[ -z $atai ] && echo $karadesu

#参照したファイルの中身が0バイトではない
[ -s $file ] && echo $nakamiGAarimasu


#ファイルか判定
[ -f $file ] && echo "file desuyo."
#ディレクトリか判定
[ -d $dir ] && echo "directory desuyo."

#ファイルが存在し、実行権限が付与されている
[[ -x `which hoge` ]] && echo "hoge dekiruyo."


# || で else文を設定できる
[ $hoge = $foo ] && echo "true" || echo "false"

# [[ ]] で囲えば 複数条件を記述可能
[[ ! -z $hoge && $piyo == "foo" ]] && out=` > $bar`

for文

基本例(ワンライナー)
for i in a a a; do echo bbb; done
# bbb
# bbb
# bbb
配列内の値を利用
arr=(el psy cong lue)
for i in ${arr[@]}
do
    echo $i
done

#el
#psy
#cong
#lue

引数全て = $* "$@"

引数の内容を全て表示(ワンライナー)
for c in $*; do echo $c; done

for c in "$@"; do echo $c; done
引数があれば実行(if_&_for)
if [[ -n $* ]]; then
    for content in $*
        do echo $content
    done
fi

while文

基本
while 条件式
dobreakdone
break条件以外は無限ループ
# hige 以外はお断り
while :
do
  read key
  [[ $key = hige ]] && break
done
clear
echo "髭!"
continueでループ継続
# hige を打っても終われない
while :;do read key;[[ $key = hige ]] && continue; done
exitで強制終了
while :
do
  read key
  exit
done
echo "じゃあの"

ワンライナー例
# while 条件式; コマンド ; done

while true ; do ps aux | grep httpd ; echo ""; sleep 2 ; done ;

while sleep 1; ls -l | wc -l ; done

while read line; do echo "${line}" done < text.txt

case文

条件部分はクォート囲みありでもなしでもおk

基本
case $1 in
  # 条件 ) コマンド ;;
  1 ) echo "(・・)" ;;
  "3" ) echo "(・・)(・・)(・・)" ;;
  8 ) echo "(・・) x 8" ;;
  * ) echo $1 ;;
esac
while文と併用してなんちゃって対話形式
while :
do
  read key
  case "$key" in
    "q" ) echo "break で終了";break ;;
    "a" ) echo "$keyやろ" ;;
    ??l* ) echo "3文字目がlやろ" ;;
    hoge ) echo "${key}やろ!" ;;
    hige ) echo "髭!" ;;
    94 ) echo "$key-95=-1" ;;
    [hH]* | [pP]* ) echo "$key 先頭が h or H or p or P の文字列" ;;
    [A-Z]* ) echo "$key 先頭が大文字の文字列" ;;
    * ) echo "$key (・⊇・)?" ;;
  esac
done

コマンドで条件分岐するにはバッククォートで括る

コマンドで条件分岐
ASTERISK="*"

# case `コマンド` in
case `echo $(($RANDOM % 100))` in
  8* ) echo " 8なんとか" ;;
  9* ) echo " ほぼ100? ほぼ10?" ;;
  *5 ) echo " 5の倍数" ;;
  * | $ASTERISK ) echo " (・⊇・)?" ;;
esac

日時を利用

出力
# 年月日時分秒
echo `date +%Y%m%d%H%M%S`
日時をファイル名に含めてファイル作成
touch test`date +%Y%m%d`.txt

指定の数値分だけ出力

for i in {1..10}; do echo $i; done

算術式展開

x=2
y=5
sum=$((x+y))

echo $sum
#7

echo $((x+y))
#7
1から100まで足す(while)
#!/bin/bash

i=1
sum=0
while [[ $i -le 100 ]]; do ((sum=sum+i)); ((i+=1)); done
echo $sum

forでやる
#!/bin/bash

sum=0
for a in {1..100}; do ((sum=sum+a)); done
echo $a

配列

文字列
arr=(hoge hoge2 hoge3)
echo ${#arr[*]}
# 3
echo ${#arr[@]}
# 3
echo ${#arr[1]}
# 2
echo ${arr[2]}
# hoge3

hoges="p pk piyo"
echo $hoges
# p pk piyo
1引いた数
arr=(hoge hoge2 hoge3)

key_max=$((${#arr[*]} - 1)) #添字の最大値を取得

文字列の切り出し(cut)

基本
# cut -d "区切り文字" -f 何列目
date
#> Sun Dec 14 20:11:45 JST 2018


## 時刻(時分秒)を 切り出し
date | cut -d " " -f 4
#> 20:11:45

## さらに 時間(hour)だけ 切り出し
date | cut -d " " -f 4 | cut -d: -f 1
#> 20

特殊記号

$#・・・・・・シェルスクリプト実行時の引数の数
$@,$*・・・シェルスクリプト実行時の全引数の変数
$$・・・・・・現在のプロセス番号(PID)

$?・・・・・・直近のコマンドの実行結果のステータスコード
$?の結果種類について

	0・・・・コマンド正常終了
	1・・・・コマンド異常終了
	2・・・・シェルスクリプトの異常終了(文法エラー、文字列の比較など)

	126・・・権限のないファイルを実行した場合のエラー
	127・・・"command not found" 時のエラー
	130・・・強制停止(Ctl-C)時のエラー

正規表現

[[]]で囲み、=~を用いて正規表現でif文とかできる。
正規表現の条件にはクォーテーションを使わないように。

=~
name=nmhogen
[[ $name =~ hoge.*$ ]] && echo hoge!
変数を利用
tel='09012345678'
reg='[0-9]{3}-?[0-9]{4}-?[0-9]{4}'
# 0~9 の 3文字-4文字-4文字 の組み合わせ

[[ $tel =~ $reg  ]] && echo $tel


==でも正規表現できる

別例
if [[ `file today_memo.txt` == *text* ]]; then echo 'text-file des4os4'; fi

ランダム(乱数)

$RANDOM(0~Nの範囲)
# $RANDOM を使う。シェルがbashかzshなら使える。shは使えない

echo $(($RANDOM % 10))
# 0 〜 9 でランダムに出力
/dev/random
# シェルの種類に関係なく乱数を使える

echo $(( $(od -vAn -N4 -tu4 < /dev/random) % 10 ))
# 0 〜 9 でランダムに出力

音(サウンドファイル)を鳴らす

:bangbang:yum でインストールできないかも?

afplay
# afplay サウンドファイルのパス
afplay ~/Desktop/hoge/piyo/foo.wav                                  

## たいていの拡張子はカバーしてるっぽい?
オプション
# 再生する時間 [秒数指定] (ファイルの再生時間より長くはできない)
afplay  -t 0.01 ファイルパス
afplay  -t 30 ファイルパス

# 音の品質 [0/1 → 低/高] (違いがわかんね)
afplay  -q 0 ファイルパス
afplay  -q 1 ファイルパス

# ファイル再生(音声・時間)を圧縮する [0は通常再生(だと思う)]
afplay  -r 0 ファイルパス
afplay  -r 50 ファイルパス

# -v [音量] は使わないほうがいい。スピーカーからHAKAIONが鳴りうるので


28
36
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?