Linux で利用できるシェルスクリプト(文字列・配列・構文などの取り扱い方)

bash

bash はシェルスクリプトの一種で、ほとんどの Linux においてデフォルトのシェルとして使われている。簡単な繰り返し処理はもちろんのこと、大量なデータを処理する際もシェルスクリプトを書いて計算機に投入する必要があるので、シェルスクリプトは Linux ユーザーにとってなくてはならない存在である。

bash の変数

bash の変数には文字列あるいは配列を代入することができる。数字を代入しても、基本的に文字列として扱われる。

seq=ACAGTTAGCTAGCTGATGCACTAGTC
echo ${seq}
## ACAGTTAGCTAGCTGATGCACTAGTC


n=10
m=20
x=${n}+${m}
echo ${x}
## 10+20


arr=("AAA" "CCC" "GGG" "TTT")
echo ${arr}
## AAA
echo ${arr[@]}
## AAA CCC GGG TTT

bash では関数を定義することも可能で、その際に function を利用して定義する。

function sum {
  let x=$1+$2
  echo ${x}
}
sum 10 20
## 30

bash 文字列

# を利用することで、文字列の長さを求めることができる。

dna="TAGCATGCAGTCTATTATCGGATCGATGCTGACTAGTCAGCT"
echo ${#dna}
## 42

文字列の切り出しは、開始位置と終了位置を指定して切り出す。

echo ${dna:0:5}
## TAGCA

文字列の置換はスラッシュを利用する。マッチしたパターンすべてに対して置換を行うときは、// を利用し、マッチしたパターンの最初の 1 つだけに対して置換を行う場合は / を利用する。

echo ${dna//T/U}
## UAGCAUGCAGUCUAUUAUCGGAUCGAUGCUGACUAGUCAGCU

echo ${DNA/T/U}
## UAGCATGCAGTCTATTATCGGATCGATGCTGACTAGTCAGCT

文字列の連結は 2 つの変数連続して書けば良い。他のプログラミング言語のように + や . などの連結演算子は存在しない。

exon1="ACCCATCAGCGCATCGTACGTAC"
exon2="ACGTGGCGTCATGATGCAGAAAA"
cds=${exon1}${exon2}
echo ${cds}
## ACCCATCAGCGCATCGTACGTACACGTGGCGTCATGATGCAGAAAA

配列の要素を連結して 1 つの文字列にする場合は、まず連結する際に区切り文字として利用される文字を IFS で指定してから、[*] で配列を展開して、新しい変数に代入すれば良い。

exons=( "AACTCAGCAT" "TTGCGTGAGCT" "ACACGCTACCA")
IFS=""
cds="${exons[*]}"
echo ${cds}
## AACTCAGCATTTGCGTGAGCTACACGCTACCA

1 つの文字列を区切り文字で分割して、配列にすることもできる。

allfeatures="CDS,mRNA,exon,exon,intron,ncRNA"
IFS=","
features=(${allfeatures})
echo ${features}
## CDS mRNA exon exon intron ncRNA

bash 配列

配列の作成

bash の配列を作るには、複数の要素を括弧で囲んで、変数に代入すれば良い。要素と要素の間はスペースで区切る。

arr=()
arr=("magnoliids" "monocots" "eudicots")

配列を作ってから、添え字を指定して要素の変更や追加を行うこともできる。

arr=()
brr=("mag" "mon" "eud")

arr[0]="NN_CC320"
echo ${arr[@]}
## NN_CC320

arr=("${brr[@]}" "NM_AC001" "NX_CB201")
echo ${arr[@]}
## mag mon eud NM_AC001 NX_CB201

arr[2]="NX_CB202"
echo ${arr[@]}
## mag mon NX_CB202 NM_AC001 NX_CB201

配列要素の取り出し

要素を取り出すときは、添え字を指定して取り出す方法の他に、開始位置と終了位置を指定して複数の要素を取り出すこともできる。

div=("FUN" "PLN" "PRT" "MAM" "HUM" "VRT")
echo ${div[0]}
## FUN
echo ${div[@]:2:2}
## PRT MAM
echo ${div[@]:2}
## PRT MAM HUM VRT
echo ${div[${#div[@]}-1]}
#VRT

配列中すべての要素を順番に取り出す場合は for を利用する。次のように、添え字を介して要素を取り出す方法と、要素自体を取り出す方法がある

div=("FUN" "PLN" "PRT" "MAM" "HUM" "VRT")

for (( i = 0; i < ${#div[@]}; ++i ))
do
    echo ${div[$i]}
done


for domain in ${div[@]}
do
    echo ${domain}
done

配列要素の置換

bash では、配列の要素に対して一括に置換などを行うことができる。ファイル名から拡張子を削除したり、あるいは拡張子を変更したりする場合に便利。

filenames=("NC_01.1.fasta" "NC_02.1.fasta" "NC_03.2.fasta")
 

# fasta を fa に置換する
echo ${filenames[@]/fasta/fa} 
## NC_01.1.fa NC_02.1.fa NC_03.2.fa


# .fasta を消す
echo ${filenames[@]/\.fasta/}   
## NC_01.1 NC_02.1 NC_03.2

 
# 先頭から最初にマッチした位置まで取り除く
echo ${filenames[@]#*\.} 
##1.fasta 1.fasta 2.fasta

 
# 先頭から最後にマッチした位置まで取り除く
echo ${filenames[@]##*\.} 
## fasta fasta fasta

 
# 末尾から最初にマッチした位置まで取り除く
echo ${filenames[@]%\.*} 
## NC_01.1 NC_02.1 NC_03.2
 

# 末尾から最後にマッチした位置まで取り除く
echo ${filenames[@]%%\.*} 
## NC_01 NC_02 NC_03

bash 関数

bash で関数を定義するときは function を利用する。関数の引数は $1$2、…のように参照する。

# 入力された二つの引数の和を出力する関数
function sum {
  let x=$1+$2
  echo ${x}
}

# 「関数名 第1引数 第2引数」のように並べて呼び出す
sum 10 20
## 30

bash の関数に戻り値がないので、戻り値利用する場合はあらかじめグローバル変数を 1 つ用意しておく必要がある。

y=""

function sum {
  let x=$1+$2
  y=${x}
}

sum 10 20
echo ${y}
## 30

bash 制御構文

if 構文

2 つの値を比較して真偽を判定してから、次の処理を行う if 構文は次のようにかける。bash の if 構文の書き方は、他のプログラミング言語のように自由度が高くないので、条件判断のところでスペースが多かったりまたは少なかったりするとエラーになる。

n=10
m=20
if [ ${n} -eq ${m} ]
    then
        echo "n = m"
elif [ ${n} -lt ${m} ]
    then
        echo "n < m"
else
        echo "n > m"
fi

for 構文

for 構文は配列の要素を 1 つずつ繰り返しながらとる出すループ構文である。

for i in 1 2 3 4 5
do
    echo $i    #1 2 3 4 5
done
 

for i in {1..5}
do
    echo $i    #1 2 3 4 5
done


for i in {1..10..2}
do
    echo $i    #1 3 5 7 9
done


for (( i=0; i<=5; i++ ))
do
    echo $i    #0 1 2 3 4 5
done


for i in {1..10}
do
    if [ $i -gt 3 ]
        then
            echo $i  #4
            break
    fi
done

while 構文

while 構文は、与えられた条件が真である限り繰り返すループ構文である。

declare -i i=0
while [ $i -lt 5 ]
do
    echo $i     #0 1 2 3 4
    let i+=1
done

ほぼ同じような機能を有する until 構文もある。until の場合は、ある条件に満たすまで繰り返すループ構文である。

declare -i i=9
until [ $i -lt 5 ]
do
    echo $i     #9 8 7 6 5
    let i-=1
done

特殊変数と演算子

bash で利用される特殊変数と演算子。

特殊変数

$0      #シェルスクリプト名
$1      #第1引数
$2      #第2引数
$#      #引数の個数
$@      #すべての引数を展開 "$1" "$2" ...
$*      #すべての引数を展開 "$1 $2 ..."
$?      #直前に実行したコマンドの終了ステータス
$!      #直前に実行したコマンドのPID
$$      #シェルスクリプトのPID

算術演算子

N + M
N - M
N * M
N / M
N % M   #剰余

論理演算子

N & M   #AND
N | M   #OR
N = M   #==
N > M   #>
N >= M  #>=
N < M   #<
N <= M  #<=
N != M  #!=

比較演算子

N -eq M
N -lt M
N -gt M
N -le M
N -ge M

サンプル

拡張子を変換

現在のディレクトリにある拡張子「fasta」で終わるファイルを「fa」に変更する例。

for i in `ls *.fasta`
do
  mv ${i} ${i%.fasta}.fa
done

ファイル名の一括変換

ファイル名に「AAA」が含んでいれば、それを「BBB」に変更する例。

for i in `ls *AAA*`
do
  mv ${i} `echo ${i} | sed 's/AAA/BBB/g'`
done

ファイルを一つにまとめる

複数の fastq ファイルを一つのファイルにまとめる例。

for i in `*.fastq`
do
  cat ${i} >> all.fastq
done

パイプで変数を利用

シェルスクリプトでパイプを利用するとき、パイプ左側の内容を変数に代入し、パイプ右側で利用することができる。while read を利用する。

echo "SRR000001 SRR000002 SRR000003" | while read line
do
    IFS=" "
    fqs=(${line})

    for f in ${fqs[@]}
    do
        echo ${f}.fq
    done
done
## SRR000001.fq
## SRR000002.fq
## SRR000003.fq

.bashrc と .bash_profile

bash の環境変数の設定やエイリアスの定義などは .bashrc あるいは .bash_profile に書く。.bashrc に書いた定義などは bash スクリプトを実行するとき、実行直前に読み込まれる。一方で、.bash_profile はログインするときにしか実行されない。

References