-
-
Save LeeDDHH/50179e3d99d1328775f6d931d48259ba to your computer and use it in GitHub Desktop.
shell scriptに関するgistのまとめ(0_shell_script_link_index)
$ コマンド オプション | echo $?
- 戻り値
1
: 実行可能0
: 実行不可能
$ which コマンド
or
$ type コマンド
or
$ where コマンド
or
$ command -v コマンド
Bashでコマンドの存在チェック - LESS IS MORE
Check If a Command/Executable Exists from Shell Script ❚ A Scripter's Notes
How can I check if a program exists from a Bash script? - Stack Overflow
$ printf "\a"
or
$ osascript -e 'beep'
or
$ echo -e "\a"
or
tput bel
open "https://scrapbox.io/camomilecafe/$(date +%Y-%m-%d)"
Bash: Mac OS X10.6でハードウェアのビープ音を鳴らす方法 | Code Hero
$ echo $0
bc
- 数字や記号をもとに、計算を処理するコマンド
$ echo 1+1 | bc
2
$ echo '2+2' | bc
4
bc
以外の計算方法
$ echo '1+1' | sed 's/.*/echo $((&))/' | zsh
$ echo '1+1' | sed 's/^/puts /' | ruby
$ echo '1+1' | sed 's/./& /g' | xargs expr
$ echo '1+1' | perl -ple '$_=eval'
$ echo '1+1' | bash -c 'echo $(($(cat)))'
$ echo '1+1' | grep -o 1 | wc -l
$ echo '1+1' | perl -e '{printf "%d\n", eval(<STDIN>)}'
$ なんかの処理 | xargs
$ file 確認したいファイルパス
- zshでは、TIMEFMTという環境変数を使って
time
の結果を表示する
$ vi ~/.zshrc
# 以下を記載する
TIMEFMT=$'\n\n========================\nProgram : %J\nCPU : %P\nuser : %*Us\nsystem : %*Ss\ntotal : %*Es\n========================\n'
$ source ~/.zshrc
- 一度読み書きしたファイルの内容はメモリの上に一時保存され、次に読み書きするときに高速に処理できるようにする仕組み
- 単にキャッシュとも呼ぶ
$ nproc
並行で走らせられる処理の数
$(コマンド)
- コマンドの出力を、引数の文字列に変換できる
- 世界で最初に実装されたシェル
- どの環境でも共通して動くPOSIXシェルを指すこともある
- bash以外でも動作するシェルスクリプトを書く場合、shで動くものを書くことが条件となる
echo $SHELL
cat /etc/shells
- $RANDOM
- 0~32767が対象
$ seq 1000 | sed 's/^/echo $RANDOM > /' | zsh
- バッファ
- 何かデータを受け渡しするときに、ある程度の量のデータをためて、あるタイミングで一度に渡す仕組み
# 1~5までの数を出力する
$ seq 5
# 5~15までの数を出力する
$ seq 5 15
# 5~15までの数を2ずつ増やしながら出力する
$ seq 5 2 15
# 5から1までの数を出力する
$ seq 5 -1 1
# 1~5までの数を出力し、逆順に並べ替える
$ seq 5 | tac
-f
オプションで数字の形式を指定できる- 使える書式
%e
- 指数形式
%E
- 大文字で出力する
%f
- 小数点形式
- 小数点以下2桁の表示までする →
%0.2f
%g
- 一般的な数値の形式
- 桁数のしていができる
- 4桁幅 →
%4g
- 4桁で前方を0で埋める →
%04g
$ seq -f "img%04g.img" 5
img0001.img
img0002.img
img0003.img
img0004.img
img0005.img
%数字s
- 文字列の指定した数になるように左へ余白が入る
$ printf "%5s\n" xx yyy zzzz
xx
yyy
zzzz
- シェル変数
- 動作中のシェル内でのみ有効な変数
set
- 環境変数
- シェルとシェル上で実行されるアプリケーションで有効な変数
printenv
- 変数を擬似的にファイルのように取り扱える
cat <<< $SHELL
cat
時に現在使っているshellを書き込む
- 複数行をコマンドに渡したり、出力したりできる
cat << EOT
- 複数行を書き込んで、終了する際に
EOT
と入力
# 以下のような表現
x
x
x
x
x
# tac catの反対で入力した行を逆順で出力する
# 出力時に改行を入れる場合はprint
# 出力時に改行を入れない場合はprintf
$ seq 5 | awk '{for(i=1;i<$1;i++){printf " "};print "x"}' | tac
$ seq 5 -1 1 | awk '{for(i=1;i<$1;i++){printf " "};print "x"}'
$ seq 5 -1 1 | awk '{printf "%*s\n", $1, "x"}'
$ sed 's/探す文字列/置換する文字列/' ファイル名
$ sed 's/探す文字列/置換する文字列/g' ファイル名
-E
オプションは、「拡張正規表現を使う」という宣言
$ sed -E 's/正規表現式/置換する文字列/g' ファイル名
- 文字列の再利用機能
- 広報参照
# %は検索対象の文字列を再利用するときに使う
$ sed 's/探す文字列/&/g' ファイル名
# ()で囲むと順番に再利用可能な番号(\数字)が与えられる
# \1,\2…
$ sed -E 's/(文字列1)(文字列2)/\2\1/g' ファイル名
- 前提
- 区切り文字を@にする
s@置換前@置換後@g
|
は拡張正規表現におけるOR記号[
と]
は正規表現で使う記号なのでエスケープ
- 区切り文字を@にする
# s@.*\[|\]|/@@g
# [以前の文字列 → .*\[
# \ → \]
# / → /
# s/:/ / → 最初に現れた:を空欄する
$ sed -E 's@.*\[|\]|/@@g;s/:/ /' access.log
-n
オプションで特定のパターンの行を抽出するsed -n '/正規表現/p'
- 正規表現にマッチした行を抽出する
sed -n '/正規表現1/,/正規表現2/p'
- 正規表現1でマッチした行から正規表現2にマッチする行までを抽出する
# 2016/12/24 21時から2016/12/25 3時までのログを抽出
$ cat log_range.log| sed -n '/24\/Dec\/2016 21:..:../,/25\/Dec\/2016 03:..:../p'
- 前提
- ファイルに以下の内容が入っている
-
aaa bbb ccc
-
- 各行の後ろに改行コードを入れる
- ファイルに以下の内容が入っている
# 方法1
$ cat xxx.txt | sed -E $'s/$/\\\n/'
# 方法2
# trコマンドで文字の置き換えをする
$ cat xxx.txt | sed -E 's/$/|/' | tr '|' '\n'
# 方法3
$ cat xxx.txt | sed -E 's/$/\'$'\n/'
cat dummy.txt | sed -e "s/^.\{2\}//"
-E
オプションは、「拡張正規表現を使う」という宣言
$ seq 100 | grep -E "^(11|22)" | xargs
11 22
-o
オプションは、その行でマッチしたもののみを表示する
$ echo 中村 山田 田代 上田 | grep -o '[^ ]田'
山田
上田
grep -R
grep -l
- デフォルトで並列処理をする
- カレントディレクトリ内のファイルすべてを検索する
# 基本的な使い方
$ rg '正規表現'
# 検索結果を表示せずにファイル名だけを出力する
$ rg -l '正規表現'
grep
にプログラム機能をつけたようなコマンドawk
はプログラミング言語- さまざまな亜種がある
- GNU Awk(
gawk
)
- GNU Awk(
- 処理を書くときの名称
- 条件 → パターン
- 処理 → アクション
- パターンとアクションの組 → ルール
- 読み込んだ行の各列の文字列、数字を指定する方法
- $1、$2、$3…
- データのn列目を第nフィールドと呼ぶ
- BEGIN、ENDパターン
- 事前、事後に
awk
でやってほしい処理を書くとき BEGIN
awk
が1行目の処理を始まる前
END
awk
が最終行の処理を終えた後
- 事前、事後に
- C言語と同じく非ゼロの値は真を指す
- 変数の宣言をせず、いきなりつかうこともできる
- 宣言されていない変数は実行直前に初期化される
awk
に慣れて、awk
でプログラムするのが面倒になったらショートカットのようにコマンドを覚えるawk
の変数NR(Number of Record)行数
- 行番号
NF(Number of Fields)列数
- 列数
$数字
$0
- 行全体
$1
、$2
、…- 各列目の値
$数字~/正規表現/
- 指定した列で正規表現にマッチしたものを対象とする
$数字!~/正規表現/
- 指定した列で正規表現にマッチしなかったものを対象とする
-F識別子
- 列の区切り文字を空白やタブから変更する
# BEGINで0の変数を宣言
# 奇数、偶数を判定し、出力する
# アクションごとに値を合算する
# アクションの終了時に合算した値を出力
$ seq 5 | awk 'BEGIN{a=0}$1%2==0{print $1,"偶数"}$1%2{print $1,"奇数"}{a+=$1}END{print "合計",a}'
1 奇数
2 偶数
3 奇数
4 偶数
5 奇数
合計 15
awk '/正規表現/'
awk
の亜種- gawk、nawk、mawkなど
- Linuxの場合、単に
awk
とコマンドを実行したとき、たいていオリジナルのawkではないawkの亜種のどれかが呼ばれる- なので、実行前に環境内の
awk
の種類を確認する必要がある awk --version
- なので、実行前に環境内の
- 行数が多く、出現する文字列の種類が少ない場合に使える
- 連想配列
a[数字] = 値
a["文字列"] = 値
# a[$1]で入力された1列目をキーに指定できる
# a["奇数"]、a["偶数"]で入る
# a[$1]++によって、値が0に初期化され、++で1にできる
# 行が入力されるごとに1増える
# for(キー in 連想配列)でfor文が使える
$ seq 5 | awk '{print $1%2 ? "奇数":"偶数"}' | awk '{a[$1]++}END{for(k in a)print k,a[k]}'
奇数 3
偶数 2
$ cat ファイルパス | awk '$1=="検索したい文字列"'
$ awk '{s += $1} END{print s}' < 数字が入っているファイルのパス
- 前提
- 時間表示は
:
で区切られている - 各行で区切られる列数は必ずしも一致するとは限らない
- 時間表示は
$ awk -F: '{print $(NF-2)}' access.log | awk '$1<"12"{print "午前"} $1>"12"{print "午後"}' | sort | uniq -c | awk '{print $2,$1}'
午前 3
午後 2
- データの中に何がいくつ存在するか集計するときに使える
sort
- 並び替える
uniq
- 重複する行を消す
-c
オプションをつけ、消したい行を連続して並べることで、数える- 同じ行がいくつ連続で存在しているのかをカウント
# sortは辞書順(abc順)に並べる
$ seq 5 | awk '{print $1%2 ? "奇数":"偶数"}' | sort
偶数
偶数
奇数
奇数
奇数
$ seq 5 | awk '{print $1%2 ? "奇数":"偶数"}' | sort | uniq -c
2 偶数
3 奇数
$ seq 5 | awk '{print $1%2 ? "奇数":"偶数"}' | sort | uniq -c | awk '{print $2,$1}'
偶数 2
奇数 3
-k 数字
のオプジョンで何列目を並べ替える基準にするのかを決める-k 2
は2列目を基準に並べ替える-k 2,2
は2列目から2列目を基準に並べ替える-k 2,2n
は2列目から2列目を基準に数値として並べ替える-k 2n
は2列目を数値として並べ替える-k 2nr
は2列目を数値として逆順に並べ替える
-n
は
# 2列目から2列目を基準に数値として並べ替える
$ seq 19 | awk '{print $1%2 ? "奇数":"偶数"}' | sort | uniq -c | awk '{print $2,$1}' | sort -k2,2n
偶数 9
奇数 10
# 2列目から2列目を基準に辞書順で並べ替える
# ただし、左から文字列が比較される
# 10と9の比較では、最初に1と9のひかくになるため、10が先になる
$ seq 19 | awk '{print $1%2 ? "奇数":"偶数"}' | sort | uniq -c | awk '{print $2,$1}' | sort -k2,2
奇数 10
偶数 9
- コマンドに引数を渡して実行してもらう役割
xargs
は渡された値を入力ではなく引数として扱う-n数字
- 数字分の個数の入力値をコマンドに渡す
-n2
なら入力値を2つずつにして渡す
I識別子となる記号
- 識別子となる記号で
xargs
が受け取った文字列を扱う
- 識別子となる記号で
-P数字
- 並列実行をする
- 数字の数だけ並列実行をする
# 1,2,3,4という名前のディレクトリを作成する
# mkdir 1 2 3 4
$ seq 4 | xargs mkdir
# ディレクトリ1,2,3,4を消去
# rmdir 1 2 3 4
$ seq 4 | xargs rmdir
# 1,3というディレクトリを事前に作って、それぞれを2,4という名前にする
# mv 1 2
# mv 3 4
$ mkdir 1 3
$ seq 4 | xargs -n2 mv
# dir_という接頭詞をつけた連番のディレクトリを作成する
$ seq 4 | xargs -I@ mkdir dir_@
- コマンドを指定されなかったときは
echo
を実行する
$ seq 10 | xargs
1 2 3 4 5 6 7 8 9 10
- 決められた列数で横に並べる
$ seq 10 | xargs -n5
1 2 3 4 5
6 7 8 9 10
- 指定する文字列によって、オプションとして解釈される場合がある
- 実行する処理の安全性の点ではあまり良いことではない
# -eをechoのオプションとして 解釈する
$ awk 'BEGIN{print "-e 1 2 3"}' | xargs
1 2 3
cat list.txt | xargs -IXXXX echo aXXXXa
-I
- コマンドの途中に挟むように入れたいときに使う
-IXXXX
とすると、XXXX
が引数に置き換わる
- 処理の中で
()
を書くことで前後の値とくっつかないようにする
# 奇数の場合はodd_、偶数の場合はeven_をつけてディレクトリを作る
$ seq 4 | awk '{print "mkdir " ($1%2 ? "odd_" : "even_") $1}' | zsh
- シェルスクリプトとして保存後、シェルコマンドで呼ぶ
$ seq 4 | awk '{print "mkdir " ($1%2 ? "odd_" : "even_") $1}' > a
$ zsh ./a
- シェルスクリプトのいち行目に書く
#!すプリプと言語のコマンドの絶対パス
#!/bin/zsh
- OSが絶対パスにあるコマンドを呼び出し、そのコマンドが2行目以降を読み込むように手配してくれる
- 実行できるように
chmod +x
でパーミッションを与える- ex) chmod +x ./a
$ find 探したいディレクトリのパス | grep 探したいファイルの文字列
$ grep '探したい文字列' ファイルパス
# catの分だけマシーンの負担は増えるが、少ない検索料であれば使える
$ cat ファイルパス | grep '探したい文字列'
# grep以外の方法
# sed -n で各行を自動的に出力しない
# sedの正規表現時に/pをつけることで、正規表現にマッチする行だけ出力する
$ cat ファイルパス | sed -n '/正規表現/p'
$ cat ファイルパス | awk '正規表現'
$ cat ファイルパス | perl -ne '正規表現 and print'
imagemagick
のconvert
を使う
$ convert 画像ファイルパス 別の画像拡張子を使ったファイルパス
$ ls *.png | sed 's/\.png$//' | xargs -I@ convert @.png @.jpg
# xargs -Pでコマンドを並列実行をする
# 「-P数字」で並列実行する数を決める
$ ls *.png | sed 's/\.png$//' | xargs -P2 -I@ convert @.png @.jpg
# nprocで並行で走らせられる処理の数だけ並列実行する
$ ls *.png | sed 's/\.png$//' | xargs -P$(nproc) -I@ convert @.png @.jpg
# imagemagickのmogrifyを使った方法
# xargsなしでファイルを一括処理できる
$ mogrify -format jpg *.png
# parallelコマンドを使った方法
# parallel 処理 ::: 操作対象1 操作対象2 …
# 操作対象に対して処理を並列に実行する
# {} ファイル名
# {.} ファイル名から拡張子を除去したもの
$ parallel 'convert {} {.}.jpg ::: *.png'
# 1~1000という名前のファイルがあるとする
$ seq 1000 | xargs -P2 touch
# 各ファイルの先頭に0をつけて4桁を揃える
# ls -Uで、ソートを省略してファイル一覧を出力する
# renameコマンドはsedのように正規表現(Perlの正規表現の書き方)でファイル名を変更する
# s/^/0000/はファイル名の先頭に一律で4つの0を付与する
# s/0*([0-9]{4})/$1/は余計な先頭の0を除去して、後ろ4桁の数字を抽出する
$ ls -U | xargs -P2 rename 's/^/0000/;s/0*([0-9]{4})/$1/'
# 並列処理で削除する
$ ls -U | xargs -P2 rm
# 対象のディレクトリごと削除する
$ rm -rf 削除するディレクトリ
# ディレクトリ内のファイルを再帰的に読み込んで、中身が10と書かれたファイルのみを削除する
$ grep -l '^10$' -R . | xargs rm
ls -1
ls -F
ls -1F | grep "/"
ls -1F | grep -v "/"
以下のような構成があるとする
.
├── a
├── b
└── c
この各ディレクトリをzipでまとめる
.
├── a
├── a.zip
├── b
├── b.zip
├── c
└── c.zip
find . \! -name '*.zip' \! -name '.' -type d -exec zip -r {}.zip {} \;
#!/bin/bash
FILE_NAME=ファイルパス
while read LINE
do
# コマンド
done < ${FILE_NAME}
- Jオプション
- replacement
- 指定した文字をパイプで受け取った文字列として展開してくれる
cat hoge | xargs -J % nantoka %
- du
- ストレージのディレクトリの容量を調べる
- オプションを指定しないと、ディレクトリ配下のファイル単位までサイズを調べる
- オプション
- d
- 表示する階層を指定する
- h
- KBやMBなど人が分かり易い単位で表示する
- d
# 現在の階層のディスク使用量を確認する
du -h -d 1
# ディスク使用量を昇順で並び変える
du -h -d 1 | sort -h
# ディスク使用量を降順で並び変える
du -h -d 1 | sort -h -r
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment