知っておくと便利なbash知識

TL;DR

便利そうなbashコマンドをまとめていきます。

基本

長い文章を出力する

cat EOF<<
long sentense!
EOF

コマンド結果を変数に格納する

$()か、``でくくる。

files=$(ls)
# or
files=`ls`

ファイルの代わりに標準入力を受け取らせて変数に格納

split=$(echo "/path/to/file" | cut -f 4 -d /)
echo $split
# file

計算系

整数の四則演算

割り算は切り捨て。

add=$((10+2))
sub=$((10-2))
time=$((10*2))
frac1=$((10/2))
frac2=$((10/3))

echo $add
# 12
echo $sub
# 8
echo $time
# 20
echo $frac1
# 5
echo $frac2
# 3

小数の四則演算

bcをつかう。

add=$(echo "1.2+1.3" | bc -l)
sub=$(echo "2.5-1.2" | bc -l)
time=$(echo "1.2*1.2" | bc -l)
frac=$(echo "10/3" | bc -l)

echo $add
# 2.5
echo $sub
# 1.3
echo $time
# 1.44
echo $frac
# 3.33333333333333333333

ファイルを取得する

# 全ファイル
files=$(ls)
# 再帰的な全ファイル
files=$(find . -type f)

# 特定の拡張子のファイル
files=$(ls *.csv)
# 再帰的な特定の拡張子のファイル
files=$(find . -type f -name '*.csv')

# 特定の拡張子を除いたファイル
files=$(ls | grep -v *.csv)

# ディレクトリのみ取得(最後に/が入るので注意)
d=$(ls -d */)
# 最後の/を除く場合
d=$(ls -d */ | sed 's/\/$//')
# 再帰的なディレクトリの取得
d=$(find . -type d)

#lsの全体のbasenameをとってくる
d=$(ls | awk -F / 'print $NF')

ファイル名を操作する

拡張子を除く

%を使うと可読性も高くて楽。後ろから見てマッチする文字列を除去できる。拡張子以外にも応用できる

filename="test.csv"
base=${filename%.csv}
# or 
base=${filename%.*}
echo $base
# test

filename="test_sorted.bam"
base=${filename%_sorted.bam}
# or
base=${filename%_*}
echo $base
# test

パスからファイル名とそれ以外を取得

basenameを使うと楽。もう一つは##を使う方法もある。こっちは前から見てマッチする文字列の最大を除去する。

path_to_file="/aa/bb/cc.csv"

# basename
filename=$(basename ${path_to_file})
# ##
filename=${path_to_file##*/}
echo $filename
# cc.csv

dir=${path_to_file%$filename}
echo $dir
# /aa/bb/

区切り文字を使ってファイル名から情報を取得する

%%は後ろから見てマッチする文字列の最大を除去する。

sample_name="aaa-bbb-ccc.csv"

# first
first=${sample_name%%-*}
# or
first=$(echo ${sample_name} | cut -f 1 -d -)
echo $first
# aaa

# ext
ext=${sample_name##*.}
# or
ext=$(echo ${sample_name} | cut -f 2 -d .)
echo $ext
# csv

# last
tmp=${sample_name%%.*}
last=${sample_name##*-}
# cutは何番目かわかっている必要がある
last=$(echo ${sample_name%%.*} | cut -f 3 -d -)

echo $last
# ccc

拡張子の一括置換

.txt -> .csv

rename .txt .csv *.txt # linuxのみ?
ls *.txt | sed -e s/\.txt// | awk '{print $1 ".txt " $1 ".csv"}' | xargs -n 2 mv

csvやtsvをある程度フォーマットした状態で読み込む

column-sはデフォルトだとtabなので、tsvなら-s以下が要らない。

cat sample.csv | column -t -s $"," | less -S

csvなどの区切り文字を変換する

csv -> tsv

cat sample.csv | tr , \\t > sample.tsv

変数が定義されているかを確認する

[ -v variable ]で確認できる。

foo="foo"

if [[ -v foo ]]; then
    echo $foo
fi

if [[ ! -v who ]]; then
    echo "who is not defined
fi

シェルスクリプト内でaliasを使う

非対話モードではaliasはデフォルトでは動かない。

man bash | grep "Alias"

Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt (see the description of shopt under SHELL BUILTIN COMMANDS below).

shopt -s expand_aliases

をすれば動く。関数で同様のことができるのでそっちを使った方が楽かもしれない。

Dockerをカレントディレクトリをマウントしつつ動かす例。

shopt -s expand_aliases
alias vdocker='docker run --rm -it -v $(pwd):$(pwd)'

# or

function vdocker {
    docker run --rm -it -v $(pwd):$(pwd) $@
}

参考

この記事に関するIssueをGithubで作成する

Read Next