プロジェクト

全般

プロフィール

ShellScript » 履歴 » バージョン 2

kanata, 2025/04/13 15:54

1 1 kanata
# ShellScript
2
3
目指せシェル芸人
4
5
{{toc}}
6
7
主にbashについて書きます
8
9
# Basic
10
11
## if文
12
13
```
14
if [ 条件1 ]
15
then
16
  処理1
17
elif [ 条件2 ]
18
then
19
  処理2
20
else
21
  処理3
22
fi
23
```
24
25
### 数値比較
26
27
|数値評価演算子  | 意味                                   |
28
|----------------|----------------------------------------|
29
|数値1 -eq 数値2 | 数値1と数値2が等しい場合に真           |
30
|数値1 -ne 数値2 | 数値1と数値2が等しくない場合に真       |
31
|数値1 -gt 数値2 | 数値1が数値2より大きい場合に真         |
32
|数値1 -lt 数値2 | 数値1が数値2より小さい場合に真         |
33
|数値1 -ge 数値2 | 数値1が数値2より大きいか等しい場合に真 |
34
|数値1 -le 数値2 | 数値1が数値2より小さいか等しい場合に真 |
35
36
こういう書き方
37
38
```
39
if [ "1" -eq "0" ]
40
```
41
42
<br><br><br><br><br>
43
44
### 文字列比較
45
46
|文字列評価演算子   | 意味                            |
47
|-------------------|---------------------------------|
48
|文字列	            | 文字列の長さが0より大きければ真 |
49
|-n 文字列          | 文字列の長さが0より大きければ真 |
50
|! 文字列           | 文字列の長さが0であれば真       |
51
|-z 文字列          | 文字列の長さが0であれば真       |
52
|文字列1 = 文字列2  | 2つの文字列が等しければ真       |
53
|文字列1 != 文字列2 | 2つの文字列が等しくなければ真   |
54
55
こういう書き方
56
57
```
58
if [ "ABC" = "abc" ]
59
if [ -z "${FILEPATH}" ]
60
if test -z "${FILEPATH}"
61
```
62
63
### ファイルチェック
64
65
|ファイルチェック演算子  | 意味                                 |
66
|------------------------|--------------------------------------|
67
|-d ファイル名           | ディレクトリなら真                   |
68
|-f ファイル名           | 通常ファイルなら真                   |
69
|-L ファイル名           | シンボリックリンクなら真             |
70
|-r ファイル名           | 読み取り可能ファイルなら真           |
71
|-w ファイル名           | 書き込み可能ファイルなら真           |
72
|-x ファイル名           | 実行可能ファイルなら真               |
73
|-s ファイル名           | サイズが0より大きければ真            |
74
|ファイル1 -nt ファイル2 | ファイル1がファイル2より新しければ真 |
75
|ファイル1 -ot ファイル2 | ファイル1がファイル2より古ければ真   |
76
77
こういう書き方
78
79
```
80
if [ -f "${FILEPATH}" ]
81
if test -f "${FILEPATH}"
82
if [ "${FILE1}" -nt "${FILE2}" ]
83
```
84
85
### 論理結合
86
87
|論理結合演算子	| 意味                                   |
88
|---------------|----------------------------------------|
89
|! 条件         | 条件が偽であれば真                     |
90
|条件1 -a 条件2 | 条件1が真、かつ、条件2が真であれば真   |
91
|条件1 -o 条件2 | 条件1が真、または、条件2が真であれば真 |
92
93
こういう書き方
94
95
```
96
# AND(論理積演算子)
97
if [ -f a.txt -a -f b.txt ]
98
if [ "$a" -eq "$b" ] && [ "$c" -eq "$d" ]
99
100
# OR(論理和演算子)
101
if [ -f a.txt -o -f b.txt ]
102
if [ "$a" -eq "$b" or "$c" -eq "$d" ]
103
if [ "$a" -eq "$b" ] || [ "$c" -eq "$d" ]
104
105
# NOT(否定論理演算子)
106
if [ ! "$a" -eq "$b" ]
107
```
108
109
### 変数に任意の文字が含まれているかどうか
110
111
```
112
if echo $WORD | grep "任意の文字" >/dev/null
113
then
114
  echo "文字含まれている"
115
else
116
  echo "文字含まれていない"
117
fi
118
```
119
120
### bashのワイルドカード
121
122
実はif文内でワイルドカードの判定ができる。
123
124
```bash
125
STRING="abc"
126
if [[ $TEST == *"b"* ]]
127
	echo "matched"
128
else
129
	echo "unmatched"
130
fi
131
```
132
133
ワイルドカード部分 * は、ダブルコーテーションで囲んだりすると動かなくなるので注意。
134
135
### bashの正規表現
136
137
そもそもgrepを使わないでも、変数に任意の文字が含まれているかどうか判定できる。
138
139
```bash
140
STRING="abc"
141
if [[ "$STRING" =~ ^ab[cd]$ ]]; then
142
	echo "matched"
143
else
144
	echo "unmatched"
145
fi
146
```
147
148
正規表現部分 \^ab[cd]$ は、ダブルコーテーションで囲んだりすると動かなくなるので注意。
149
150
## 展開
151
152
bash入門
153
https://rat.cis.k.hosei.ac.jp/article/linux/bash_intro.html
154
155
### ブレース展開
156
157
カンマ区切りの文字列をブレースで囲んだものはブレース展開されます。
158
159
```
160
$ echo {a,b,c}
161
a b c
162
```
163
164
ブレースの前後に文字列があるとそれを反映した展開がなされます。
165
166
```
167
$ echo 0{a,b,c}1
168
0a1 0b1 0c1
169
```
170
171
ブレース展開はまとめてファイルやディレクトリを作成するときなどによく使われます。
172
173
```
174
$ find . -type d
175
.
176
177
$ mkdir -p a/b{0,1}/c{0,1}
178
$ find . -type d
179
.
180
./a
181
./a/b0
182
./a/b0/c0
183
./a/b0/c1
184
./a/b1
185
./a/b1/c0
186
./a/b1/c1
187
```
188
189
### チルダ展開
190
191
チルダはユーザーのホームディレクトリに展開されます。
192
193
```
194
$ whoami
195
user1
196
$ echo ~
197
/home/user1
198
```
199
200
### ファイル名展開
201
202
ファイル名展開はグロブ(glob)とも呼ばれます。
203
204
| パターン | 効果                                                                                                    |
205
|----------|---------------------------------------------------------------------------------------------------------|
206
| *        | 0文字以上の任意の文字列にマッチ。                                                                       |
207
| ?        | 1文字の任意の文字列にマッチ。                                                                           |
208
| [...]    | ブラケットで挟まれている文字のうち任意の1文字にマッチ。正規表現におけるブラケットの解釈とほぼ同じです。 |
209
210
211
```
212
$ ls
213
a  adc.txt  aec.txt  b
214
215
$ echo *
216
a adc.txt aec.txt b
217
218
$ echo ?
219
a b
220
221
$ echo a[abcd]*
222
adc.txt
223
224
# マッチするものが無かった場合パターンはそのままの形で残ります
225
$ echo xyz*
226
xyz*
227
```
228
229
### 変数展開
230
231
変数を参照する場合に文字列を加工することができる。
232
233
| パターン                | 効果                                                                                 |
234
|-------------------------|--------------------------------------------------------------------------------------|
235
| ${変数名#word}          | 変数から値を取り出し、その先頭部分がwordと一致した場合その部分を取り除きます。(先頭から前方最短一致した位置まで) |
236
| ${変数名##word}         | 変数から値を取り出し、その先頭部分がwordと一致した場合その部分を取り除きます。(先頭から前方最長一致した位置まで) |
237
| ${変数名%word}          | 変数から値を取り出し、その後方部分がwordと一致した場合その部分を取り除きます。(末尾から後方最短一致した位置まで) |
238
| ${変数名%%word}         | 変数から値を取り出し、その後方部分がwordと一致した場合その部分を取り除きます。(末尾から後方最長一致した位置まで) |
239
| ${変数名/pattern/word}  | 変数から値を取り出し、最初にpatternとマッチする部分だけをwordで置換します。          |
240
| ${変数名/#pattern/word} | 変数から値を取り出し、最初にpatternとマッチする部分だけをwordで置換します。(上と同じ)|
241
| ${変数名/%pattern/word} | 変数から値を取り出し、最後にpatternとマッチする部分だけをwordで置換します。          |
242
| ${変数名//pattern/word} | 変数から値を取り出し、patternとマッチする全ての部分をwordで置換します。              |
243
| ${変数名:=word}         | 変数が NULL の場合 word に置換され、かつ変数に代入される。                           |
244
| ${変数名:-word}         | 変数が NULL の場合 word を出力する。                                                 |
245
| ${変数名:+word}         | 変数が NULL 以外の場合 word に置換され、かつ変数に代入される。                       |
246
| ${変数名:?word}         | 変数が NULL の場合、標準エラー出力にwordを表示し、現在実行中のスクリプトを中止する。 |
247
| ${#変数名}              | 変数に設定されている文字数を返す。                                                   |
248
| ${変数名:offset}        | 変数に設定されているoffset文字+1から出力する。offsetを負の値にすると語尾から数える。 |
249
| ${変数名:offset:length} | 変数に設定されているoffset文字+1からlength分出力する。                               |
250
| ${変数名,}              | 先頭だけ小文字に変換                                                                 |
251
| ${変数名,,}             | 全部小文字に変換                                                                     |
252
| ${変数名\^}              | 先頭だけ大文字に変換                                                                |
253
| ${変数名\^\^}             | 全部大文字に変換                                                                   |
254
255
### 算術式展開
256
257
expr や、bcコマンドを使用しなくても、$((計算式))で計算ができる。
258
259
```
260
$ echo $(( 1 + 2 + 3 ))
261
6
262
```
263
264
Qiita - Bash $((算術式)) のすべて
265
https://qiita.com/akinomyoga/items/2dd3f341cf15dd9c330b
266
267
268
### コマンド置換
269
270
コマンド置換には以下の 2 つの形式があります。
271
272
```
273
$(command)
274
`command`
275
```
276
277
今までは一般的にバッククォート `command` が使われてきたが、$(command) も使えます。
278
$(command)は、入れ子ができるので、$(command)の方を使ったほうが良い。
279
280
~~~
281
$ TEST=`date`;echo $TEST
282
2016年 8月 28日 日曜日 18:04:33 JST
283
$ TEST=$(date);echo $TEST
284
2016年 8月 28日 日曜日 18:04:41 JST
285
~~~
286
287
次のコマンドはカレントディレクトリの中で「abc」を含むすべてのファイルの先頭10行を表示します。
288
289
```
290
$ head -10 $(grep -l abc *)
291
```
292
293
### ヒアドキュメント
294
295
こんな感じ。ftpぐらいなら自動化できる。
296
297
```bash
298
$ command << token
299
text
300
token
301
```
302
303
304
305
```bash
306
#!/bin/bash
307
308
# Script to retrieve a file via FTP
309
310
FTP_SERVER=ftp.nl.debian.org
311
FTP_PATH=/debian/dists/lenny/main/installer-i386/current/images/cdrom
312
REMOTE_FILE=debian-cd_info.tar.gz
313
314
ftp -n << _EOF_
315
open $FTP_SERVER
316
user anonymous me@linuxbox
317
cd $FTP_PATH
318
hash
319
get $REMOTE_FILE
320
bye
321
_EOF_
322
```
323
324
### ヒアストリング
325
326
変数を擬似的にファイルのように扱える。
327
328
```
329
$ cat < hoge
330
-bash: hoge: そのようなファイルやディレクトリはありません
331
 cat <<< hoge
332
hoge
333
$ HOGE=hogefuga
334
$ cat < $HOGE
335
-bash: hogefuga: そのようなファイルやディレクトリはありません
336
$ cat <<< $HOGE
337
hogefuga
338
```
339
340
## 特殊なシェル変数
341
342
| 変数 | 内容                                                 |
343
|------|------------------------------------------------------|
344
| $0   | 実行したスクリプトの文字列                           |
345
| $1, $2, ..., $9 | 第1引数, 第2引数, ..., 第9引数            |
346
| $#   | 与えられた引数の数                                   |
347
| $*   | 与えられたすべての引数. 引数全体が"で囲まれている    |
348
| $@   | 与えられたすべての引数. 引数一つ一つが"で囲まれている|
349
| $-   | シェルに与えられたフラグ                             |
350
| $?   | 最後に行ったコマンドの戻り値                         |
351
| $$   | 現在のシェルのプロセス番号                           |
352
| $!   | 最後にバックグラウンドで行ったコマンドのプロセス番号 |
353
| $_   | 実行シェルの文字列                                   |
354
| IFS  | 区切り文字のリスト                                   |
355
356
357
## シェル変数と環境変数
358
359
|            | 特徴                                   | 確認 | 設定                              | 削除 | 
360
|------------|----------------------------------------|------|-----------------------------------|------|
361
| シェル変数 | シェル変数は子プロセスに引き継がれない | set  | 変数名=値                         | unset # シェル変数、環境変数両方消去される
362
| 環境変数   | シェル変数は子プロセスに引き継がれる   | env  | export 変数名 or export 変数名=値 |unset # シェル変数、環境変数両方消去される
363
364
>ちなみに、環境変数を定義するには export コマンド以外にも declare コマンドに -x オプションを付けて実行する方法もある。
365
366
367
## プロセス置換
368
369
以下の文法に従えば、コマンドの実行結果を一時ファイルに吐いておく必要がなくなる。
370
371
~~~
372
<(command)
373
~~~
374
375
376
377
~~~
378
$ sdiff <(date;sleep 1;date) <(date;date)
379
2016年  8月 28日 日曜日 18:00:15 JST                            2016年  8月 28日 日曜日 18:00:15 JST
380
2016年  8月 28日 日曜日 18:00:16 JST                          | 2016年  8月 28日 日曜日 18:00:15 JST
381
~~~
382
383
## 連想配列
384
385
連想配列が使える。
386
387
>ver4系から使える機能です。Macのbashはver3系のため、brew等でアップデートしましょう。
388
389
```
390
$ declare -A hashTable
391
$ hashTable["hoge"]="fuga"
392
$ echo ${hashTable["hoge"]}
393
fuga
394
```
395
396
# bash開発機能
397
398
## 文法チェック
399
400
```
401
$ bash -n test.sh
402
```
403
404
## 実行内容をトレース
405
406
```
407
$ bash -x test.sh
408
```
409
410
## ステップ実行
411
412
擬似シグナルDEBUGを使う。擬似シグナルDEBUGはシェルが文を実行するたびに発行される。
413
414
```
415
#!/bin/bash
416
417
trap 'read -p "next(LINE:$LINENO)>> $BASH_COMMAND"' DEBUG
418
```
419
420
## 未定義の変数をエラーとして扱う
421
422
```
423
#!/bin/bash
424
set -u
425
426
# ${TEST}が未定義ならエラーになる
427
echo ${TEST}
428
```
429
430
## 終了ステータスが0以外ならその時点で終了
431
432
```
433
#!/bin/bash
434
set -e
435
436
#ls -yでエラーになり、後続の処理は実行されない
437
ls -y
438
ls -l
439
```
440
441
442
443
# Sample
444
445
## ファイルを一行ずつ読み込んで処理する
446
447
```
448
#!/bin/sh
449
# ファイルを1行ずつ読み込んで表示
450
451
TESTFILE=./hoge.txt
452
while read LINE
453
do
454
    echo $LINE
455
done < $TESTFILE
456
```
457
458
処理単位も行にしたい時は、冒頭に以下を書く
459
460
```
461
IFS='
462
'
463
```
464
465
## 区切り文字(デミリタ)で区切られた文字列の任意のフィールドを取得する
466
467
cut方式とawk方式がある
468
469
```
470
echo "abc:def:ghi:jkl"|cut -d: -f3
471
echo "abc:def:ghi:jkl"|awk -F':' '{print $3}'
472
```
473
474
ダブルクォーテーションで囲まれている場合
475
476
```
477
$ grep 設定項目名 設定ファイル | sed 's/[^"]*"\([^"]*\)"[^"]*/\1/g'
478
```
479
480
シングルクォーテーションで囲まれている場合
481
482
```
483
$ grep 設定項目名 設定ファイル | sed "s/[^']*'\([^']*\)'[^']*/\1/g"
484
```
485
486
イコールで定義している場合
487
488
```
489
$ grep 検索する設定項目 設定ファイルPATH | sed 's/ //g' | awk -F'=' '{ print $2}'
490
```
491
492
## 標準入力とファイルの内容を結合
493
494
495
~~~
496
$ cat test
497
efg
498
$ echo -n abcd |cat - test
499
abcdefg
500
~~~
501
502
>大抵のコマンドには - (標準入力の内容をファイル相当として扱う)を実装している
503
504
505
## サーバと連続でやりとりするシェルスクリプト
506
507
以下は、サーバからもらった計算式を計算して、送り返している例
508
509
```
510
#!/bin/sh
511
512
exec 5<>/dev/tcp/[host]/[port]
513
514
for I in {1..101}
515
do
516
  cat 0<&5>test.txt &
517
  sleep 1
518
  pkill cat
519
  WORD=`cat test.txt|tail -1|sed 's/=//g'`
520
  ANSWER=`ecgo ${WORD}|bc`
521
  echo ${ANSWER} > &5
522
  echo Debug [${I}] ${WORD} '=' ${ANSWER}
523
done
524
525
exit 0
526
```
527
528
## 文字列⇔16進数表現⇔2進数表現
529
530
文字列→16進数表現
531
532
```
533
echo "ABC"|xxd
534
```
535
536
文字列→2進数表現
537
538
```
539
echo "ABC"|xxd -b
540
```
541
542
16進数表現→文字列
543
544
```
545
echo 4142434445464748 | xxd -ps -r
546
```
547
548
16進数表現→2進数表現
549
550
```
551
echo 4142434445 | xxd -ps -r|xxd -b
552
```
553
554
2進数表現→16進数表現
555
556
```
557
echo "obase=16; ibase=2; 010000010100001001000011010001000100010100001010" | bc
558
```
559
560
2進数表現→文字列
561
562
```
563
echo "obase=16; ibase=2; 010000010100001001000011010001000100010100001010" | bc|xxd -ps -r
564
```
565
566
----
567
568
bcコマンドなくても、このぐらいはできる。
569
570
2進数表現→10進数表現
571
572
```
573
echo $((2#101010))
574
echo "obase=10; ibase=2; 101010" | bc
575
```
576
577
8進数表現→10進数表現
578
579
```
580
echo $((04567))
581
echo "obase=10; ibase=8; 4567" | bc
582
```
583
584
16進数表現→10進数表現
585
586
```
587
echo $((0xABCD))
588
echo "obase=10; ibase=16; ABCD" | bc
589
```
590
591
## 指定した相対PATHからの、絶対パス・ディレクトリ名・ファイル名の取得
592
593
```
594
$ cd /tmp/trash
595
$ readlink  -f test.txt 
596
/tmp/trash/test.txt
597
$ dirname `readlink  -f test.txt`
598
/tmp/trash
599
$ basename `readlink  -f test.txt`
600
test.txt
601
```
602
603
604
## IPアドレスの取得
605
606
いろんな方法があるが、NICのインタフェース名が不定だし、複数NICが刺さっていたりもするので、これという方法が無い。
607
608
```
609
$ ifconfig eth1 | grep -w 'inet' | cut -d: -f2 | awk '{ print $1}'
610
$ ip addr list venet0 | grep "inet " | cut -d' ' -f6 | cut -d/ -f1
611
$ ip a s | grep "inet " | cut -d' ' -f6 | cut -d/ -f1
612
$ hostname -i
613
$ hostname -I
614
```
615
616
実は[こういう技](https://ex1.m-yabe.com/archives/4638)がある
617
素晴らしい
618
619
```
620
$ curl ifconfig.io
621
```
622
623
624
625
## IPアドレスのソート
626
627
```
628
$ cat ip_list.txt | sort -n -t'.' -k1,1 -k2,2 -k3,3 -k4,4
629
```
630
631
## 特定のファイルのバックアップファイルを作成する
632
633
```
634
$ find PATH -type f -name 'ファイル名' | xargs -n 1 -I{} cp {} {}.bk
635
```
636
637
## 特定のファイルをバックアップディレクトリにコピーする
638
639
```
640
$ find PATH -type f -name 'ファイル名' | xargs -n 1 -I{} cp {} バックアップ先PATH
641
```
642
643
## 特定のファイルに対してのみgrepを行う
644
645
```
646
$ find PATH -type f -name 'ファイル名' | xargs -n 1 -I{} grep '検索キーワード' {}
647
```
648
649
## 指定したファイルの合計サイズを取得する
650
651
```
652
$ du -bhc [ファイルPATH等条件] | tail -n 1
653
```
654
655
または
656
657
```
658
$ ls -la [ファイルPATH等条件] | awk '{ total += $5 }; END { print total }'
659
```
660
661
## 対話型コマンドを自動実行する
662
663
対話中に判断や計算が入るとexpectでやるしかない。
664
665
```
666
#!/bin/expect -f
667
668
spawn ./121-calculation
669
670
set i 0
671
while {$i <= 100000} {
672
673
puts "\n#### $i ######"
674
675
expect "*="
676
set quest $expect_out(buffer)
677
678
set answer [exec echo $quest | tail -1 | tr -d '=' | tr -d '\r' | bc]
679
send "$answer\n"
680
681
incr i 1
682
}
683
```
684
685
命令解説
686
687
* spawn コマンド実行
688
* puts 画面表示(実行したコマンドには影響しない)
689
* expect コマンド出力する文字にマッチングするまでここで止まる
690
* set 変数 定数 変数設定
691
* set 変数 $expect_out(buffer) コマンド実行結果を変数に(ただし、直前のではなく、全部入るっぽい)
692
* set 変数 [外部コマンド] 外部コマンドの実行結果を変数に(最新行を選択するtail -1 と 変な改行コード入ってエラーになるので tr -d '\r' を入れるのがコツ)
693
* send "変数名\n" コマンドに実行結果を送る(データ終端を\nにしているコマンドが多いので、明示的に\nを書く)
694
* incr 変数名 定数 加算
695
696
## どういう形式で圧縮されているか判別して展開する
697
698
環境合わせて、適当に修正が必要
699
700
```
701
#!/bin/sh
702
703
LIST=`ls|grep -v flatting.sh`
704
705
for WORD in ${LIST}
706
do
707
  FILE_TYPE=`file ${WORD}`
708
709
  if echo ${FILE_TYPE}|grep "Zip archive data" >/dev/null
710
  then
711
    unzip ${WORD}
712
    rm ${WORD}
713
  elif echo ${FILE_TYPE}|grep "shell archive text" >/dev/null
714
  then
715
    sh ${WORD}
716
    rm ${WORD}
717
  elif echo ${FILE_TYPE}|grep "bzip2 compressed data" >/dev/null
718
  then
719
    bunzip2 -c ${WORD} > ${WORD}_out
720
    rm ${WORD}
721
  elif echo ${FILE_TYPE}|grep "POSIX tar archive" >/dev/null
722
  then
723
    tar xvf ${WORD}
724
    rm ${WORD}
725
  elif echo ${FILE_TYPE}|grep "gzip compressed data" >/dev/null
726
  then
727
    gunzip -c ${WORD} > ${WORD}_out
728
    rm ${WORD}
729
  elif echo ${FILE_TYPE}|grep "xz compressed data" >/dev/null
730
  then
731
    xz -d -c ${WORD} > ${WORD}_out
732
    rm ${WORD}
733
  elif echo ${FILE_TYPE}|grep "ASCII cpio archive" >/dev/null
734
  then
735
    cpio -idv < ${WORD}
736
    rm ${WORD}
737
  elif echo ${FILE_TYPE}|grep "ASCII text" >/dev/null
738
  then
739
    if cat ${WORD} |grep "This is dummy file" >/dev/null
740
    then
741
      rm ${WORD}
742
    else
743
      base64 -d ${WORD} > ${WORD}_out  
744
      if [ ${?} = 0 ]
745
      then
746
        rm ${WORD}
747
      fi
748
    fi
749
  else
750
    :
751
  fi
752
753
done
754
755
exit 0
756
```
757
758
## 一定時間ごとに任意のコマンドを実行する
759
760
もちろんwatchコマンドを使ってもいいが、以下の方法でも可能。
761
762
```
763
$ yes '[任意のコマンド]; sleep [任意のインターバル秒数];' | sh
764
```
765
766
## 文字列への色つけ
767
768
```
769
txtund=$(tput sgr 0 1)    # Underline
770
txtbld=$(tput bold)       # Bold
771
txtred=$(tput setaf 1)    # Red
772
txtgrn=$(tput setaf 2)    # Green
773
txtylw=$(tput setaf 3)    # Yellow
774
txtblu=$(tput setaf 4)    # Blue
775
txtpur=$(tput setaf 5)    # Purple
776
txtcyn=$(tput setaf 6)    # Cyan
777
txtwht=$(tput setaf 7)    # White
778
txtrst=$(tput sgr0)       # Text reset
779
780
echo "${txtbld}This is bold text output from shell script${txtrst}"
781
```
782
783
## プログレスバーの表示
784
785
```
786
show_progress() {
787
    echo -ne '#####                     (33%)\r'
788
    sleep 1
789
    echo -ne '#############             (66%)\r'
790
    sleep 1
791
    echo -ne '#######################   (100%)\r'
792
    echo -ne '\n'    
793
}
794
```
795
796
## スピナーの表示
797
798
```
799
show_spin () {
800
  rotations=3
801
  delay=0.1
802
  for i in `seq 0 $rotations`; do
803
    for char in '|' '/' '-' '\'; do
804
      echo -n $char
805
      sleep $delay
806
      printf "\b"
807
    done
808
  done
809
}
810
```
811
812
## あらゆるファイルの解凍
813
814
```
815
function extract {
816
 if [ -z "$1" ]; then
817
    # display usage if no parameters given
818
    echo "Usage: extract <path/file_name>.<zip|rar|bz2|gz|tar|tbz2|tgz|Z|7z|xz|ex|tar.bz2|tar.gz|tar.xz>"
819
 else
820
    if [ -f $1 ] ; then
821
        # NAME=${1%.*}
822
        # mkdir $NAME && cd $NAME
823
        case $1 in
824
          *.tar.bz2)   tar xvjf ../$1    ;;
825
          *.tar.gz)    tar xvzf ../$1    ;;
826
          *.tar.xz)    tar xvJf ../$1    ;;
827
          *.lzma)      unlzma ../$1      ;;
828
          *.bz2)       bunzip2 ../$1     ;;
829
          *.rar)       unrar x -ad ../$1 ;;
830
          *.gz)        gunzip ../$1      ;;
831
          *.tar)       tar xvf ../$1     ;;
832
          *.tbz2)      tar xvjf ../$1    ;;
833
          *.tgz)       tar xvzf ../$1    ;;
834
          *.zip)       unzip ../$1       ;;
835
          *.Z)         uncompress ../$1  ;;
836
          *.7z)        7z x ../$1        ;;
837
          *.xz)        unxz ../$1        ;;
838
          *.exe)       cabextract ../$1  ;;
839
          *)           echo "extract: '$1' - unknown archive method" ;;
840
        esac
841
    else
842
        echo "$1 - file does not exist"
843
    fi
844
fi
845
}
846
```
847
848
> このコマンドも有用と思われ
849
850
俺的備忘録 〜なんかいろいろ〜 - ファイルの圧縮方式に合わせて自動的に解凍してくれる『dtrx』コマンド
851
https://orebibou.com/2016/07/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E5%9C%A7%E7%B8%AE%E6%96%B9%E5%BC%8F%E3%81%AB%E5%90%88%E3%82%8F%E3%81%9B%E3%81%A6%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB%E8%A7%A3%E5%87%8D%E3%81%97%E3%81%A6/
852
853
## POSIX仕様の中でif文中でパターンマッチングする
854
855
```
856
if [ -n "$X" -a -z "${X%%pattern}" ] ; then echo "true"; else echo "false"; fi
857
```
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
# KnowHow
875
876
シェルスクリプトを極める
877
http://www.slideshare.net/bsdhack/ss-43064758
878
879
## バッファリングさせない
880
881
stdoutがttyじゃないとbufferingするコマンドは多い
882
stdbufで解決できる
883
884
885
```
886
$ command | stdbuf -oL command | command
887
```
888
889
>行単位でバッファを吐き出す
890
891
```
892
$ command | stdbuf -oO command | command
893
```
894
895
>バッファリングさせない
896
897
898
以下が神解説です
899
900
俺的備忘録 〜なんかいろいろ〜 - sedやawk、grepをバッファさせずに動作させる
901
https://orebibou.com/2017/06/sed%e3%82%84awk%e3%80%81grep%e3%82%92%e3%83%90%e3%83%83%e3%83%95%e3%82%a1%e3%81%95%e3%81%9b%e3%81%9a%e3%81%ab%e5%8b%95%e4%bd%9c%e3%81%95%e3%81%9b%e3%82%8b/
902
903
904
## ファイルディスクリプタ
905
906
* 標準入力は 0
907
* 標準出力は1
908
* 標準工ラー出力は2
909
910
シエルではリダイレクト記号の前に数字
911
912
```
913
 &> ファイル  # 標準出力・標準エラー出力を共にリダイレクト
914
 3> ファイル  # fd3をファイルにリダイレクト
915
 4< ファイル  # fd4をファイルからリダイレクト
916
 5<&-         # fd5をクローズ 
917
 6>&7         # fd7をfd6に複製(fd6をfd7にリダイレクト)
918
```
919
920
---
921
実装
922
923
924
```
925
command > file
926
```
927
928
>結果、fdが標準出力として使用される
929
930
```
931
command > file 2>&1
932
```
933
934
>結果、fdが標準出力、および、標準エラー出力として使用される
935
936
```
937
commandA |commandB
938
```
939
940
>結果、commandA の標準出力が commandB の標準入力になる
941
942
943
```
944
$ ./echo "test" 3>&1 1>&2 2>&3
945
```
946
947
>標準エラー出力と標準出力を入れ替える
948
949
950
951
## プロセスの出力同士をdiffで比較
952
953
```
954
$ diff <(commandA)<(commandB)
955
956
$ commandA|(commandB|diff /dev/fd/3 -) 3<&0
957
```
958
959
> 3<&0 で標準入力(fd0) を fd3 に複製
960
> commandA の出力が fd3 に出力される
961
> /dev/fd/3 からの入力が commandA の出力
962
963
## パイプの途中のプロセスの終了コード
964
965
```
966
$ exec 3>&1 
967
ret1=`{ { commandA 1; echo $? 1>&3; } | commandB 2; } 3>&1` 
968
ret2=$?
969
```
970
971
> コマンド 1 の $? を 1>&3 で fd3 に出力
972
> fd3 の内容を 3>&1 で ret1 に格納
973
974
## ループ処理でのファイルディスクリプタの活用
975
976
```
977
exec 3<&0 0<<EOF
978
 `command` 
979
EOF 
980
while read line 
981
do
982
  : 
983
done 
984
exec 0<&3 3<&-
985
```
986
>exec 3<&0 で fd0 を fd3 に複製 
987
>exec 0<<EOF でヒアドキュメントを fd0 として使用 
988
>exec 0<&3 で複製した fd0 を復帰 
989
>exec 3<&- で fd3 をクローズ 
990
>パイプを使わないのでプロセスが生成されない
991
992
993
## evalを用いた配列的な変数アクセス
994
995
```
996
# $1: 配列名 
997
# $2: インデックス 
998
# $3-: 値 
999
1000
setarray() 
1001
{
1002
  _index_="__`echo $1 $2 | sed -e 's/ //g'`"
1003
  shift 2
1004
  eval $_index_'='"$@" 
1005
}
1006
1007
getarray() 
1008
{
1009
  eval echo '${'__`echo $* | sed -e 's/ //g'`'}' 
1010
}
1011
```
1012
1013
## ファイルの上書き
1014
1015
元ファイルを書き替える
1016
1017
```
1018
$ コマンド < ファイル > ファイル # 絶対ダメ!
1019
$ (rm ファイル ; コマンド > ファイル ) < ファイル # ファイルの中身が消えない方法
1020
        ②                     ③          ①
1021
```
1022
1023
>① でファイルが読み込みモードでオープンされる。
1024
>② でオープンされたファイルが削除される。
1025
>③ で新しい(別な)ファイルが書き込みモードでオープンされる。 
1026
1027
①のファイルと③のファイルは同じファイル名ですが、 inode が異なっているため、別のファイルとして扱われる。
1028
1029
1<>を使う方法もある
1030
1031
```
1032
cat srcfile 1<> srcfile
1033
```
1034
1035
## シェルスクリプトでの排他処理
1036
1037
```
1038
lockfile="/var/tmp/`basename ${0}`" 
1039
test -f ${lockfile} || touch ${lockfile}
1040
```
1041
1042
>test(1) と touch(1) の間に他のプロセスの test(1) が実行されると 排他処理が失敗する 
1043
1044
```
1045
lockfile="/var/tmp/`basename ${0}`" 
1046
if ln -s $$ ${lockfile} 2> /dev/null 
1047
then
1048
  : # メイン処理を実行 
1049
else
1050
  echo "${0}: exist another instance" 1>&2 
1051
  exit 255 
1052
fi 
1053
trap 'rm -f ${lockfile}; exit' 0 1 2 3 11 15
1054
```
1055
1056
>シンボリックリンクの作成は atomic
1057
>PID をリンクする事でロックしたプロセスが特定できる 
1058
1059
## 英単語の先頭文字を大文字に変換する
1060
1061
```
1062
$ echo "foo" | awk '{ print toupper(substr($0, 1, 1)) substr($0, 2, length($0) - 1) }'
1063
```
1064
1065
>awk 組み込みの substr() 、 toupper() を使用する 
1066
1067
```
1068
$ eval eval `echo "foo" | sed 's/(.)(.*)//bin/echo -n 1 | tr "[a-z]" "[A-Z]"; echo 2/g'`
1069
```
1070
1071
>sed 単体では実現できないのでコマンド列を出力して eval
1072
1073
```
1074
$ echo foo bar buz|sed 's/\b\([a-z]\)/\U\1/g'
1075
```
1076
1077
>実はsed単体でできました
1078
1079
## IF文のような分岐処理をワンライナーで行わせる
1080
1081
```
1082
$ コマンド && TRUE || FALSE
1083
```
1084
1085
「&&」以降はコマンドがTRUEの場合に、「||」以降はFALSEの場合に実行されるコマンドとなる。
1086
1087
1088
1089
```
1090
$ cat test.log 
1091
abc [31/Oct/2015:20:36:51 +0900] ghi [20]
1092
jkl [31/Oct/2015:20:36:55 +0900] pqr [0]
1093
stu [31/Oct/2015:20:37:00 +0900] yz  [40]
1094
000 [31/Oct/2015:20:37:05 +0900] ghi [5]
1095
$ grep abc test.log >/dev/null && echo 1 || echo 2
1096
1
1097
$ grep azc test.log >/dev/null && echo 1 || echo 2
1098
2
1099
```
1100
1101
1102
## exの活用
1103
1104
ファイルの行操作に ex を活用する
1105
1106
- 直接行の追加や削除が可能(一時ファイル不要)
1107
– 実は vi なので正規表現など強力な編集操作が可能
1108
– echo やヒアドキュメントで編集コマンドを指定可能
1109
1110
### exで行の追加
1111
1112
```
1113
$ /bin/ex -s ファイル << EOF
1114
行番号 a
1115
コンテンツ
1116
コンテンツ
1117
    :
1118
.
1119
w!
1120
EOF
1121
```
1122
1123
>行番号で指定した行の下にコンテンツを挿入する
1124
> . で挿入モードを終了し w! で内容をファイルに出力する
1125
1126
### exで行削除処理
1127
1128
```
1129
$ /bin/ex -s ファイル << EOF
1130
行番号 d
1131
w!
1132
EOF
1133
```
1134
1135
>行番号で指定した行を削除する
1136
> w! で内容をファイルに出力する
1137
1138
### exで行番号を指定した行置換処理
1139
1140
```
1141
$ /bin/ex -s ファイル << EOF
1142
行番号 s/パターン/置換文字列/
1143
w!
1144
EOF
1145
```
1146
1147
>行番号で指定した行のパターンを置換文字列に置換する
1148
> w! で内容をファイルに出力する
1149
1150
### exでパターンを指定した行置換処理
1151
1152
```
1153
$ /bin/ex -s ファイル << EOF
1154
/パター /s/ 置換文字 /
1155
w!
1156
EOF
1157
```
1158
1159
>最初に発見したパターンを置換文字列に置換する
1160
>s の後ろの連続した // は直前の正規表現(パターン)を示す
1161
> w! で内容をファイルに出力する
1162
1163
### exでファイルから指定された行を削除する 
1164
1165
```
1166
$ cat basefile
1167
first line
1168
second line
1169
third line
1170
    :
1171
    :
1172
1173
1174
$ cat target
1175
2
1176
3
1177
5
1178
:
1179
:
1180
1181
1182
```
1183
1184
>元のファイル (basefile) には複数の行が含まれている
1185
>削除する行は別なファイル (target) に格納されている
1186
>target ファイルには行番号が 1 行ずつ格納されている
1187
1188
パターンを指定した行置換処理
1189
1190
```
1191
$ sort target | awk '{ printf "%ddn", $1-(NR-1); } END { print "w!" }' | ex -s basefile
1192
```
1193
1194
>削除済みの行を考慮する必要がある
1195
>>→ 2 行目を削除すると今までの 3 行目が 2 行目になる
1196
>ex で行を削除する
1197
1198
>awk で削除した行を考慮した行番号に対する行削除を出力 
1199
1200
1201
1202
## シェルスクリプトで標準入力を受け取る
1203
1204
3パターンある。
1205
1206
### cat - で 標準入力を受け取り、利用できる。
1207
1208
```
1209
#!/bin/sh
1210
if [ -p /dev/stdin ] ; then
1211
    a=$(cat -)
1212
    echo "input string is ${a}"
1213
else
1214
    echo "nothing stdin"
1215
fi
1216
```
1217
1218
### readを使うと、標準入力を読むことができる
1219
1220
```
1221
#!/bin/bash
1222
while read i ; do
1223
    #数字を読み込んで1足して出力する。
1224
    echo $((i+1))
1225
done
1226
```
1227
1228
他の方法に比べて高コストになりがち
1229
1230
### /dev/stdinを使う
1231
1232
```
1233
#!/bin/bash
1234
awk '{print $1+1}' < /dev/stdin
1235
```
1236
1237
## 一時ファイルを作らずにコマンドの出力結果を利用する(Command Substitution)
1238
1239
<(コマンド)記法、ksh、bash、zsh限定。
1240
1241
コマンドに対する入出力を、ファイルのように指定することが出来る。
1242
1243
* コマンドの標準出力を入力ファイルとして <(コマンド)
1244
* コマンドの標準入力を出力ファイルとして >(コマンド)
1245
1246
例えば、
1247
1248
```
1249
$ diff <(ls) <(ls -a)
1250
```
1251
1252
これと同義
1253
1254
```
1255
$ ls > a
1256
$ ls -a > b
1257
$ diff a b
1258
```
1259
1260
## パイプラインに任意の値を入れ込む
1261
1262
### 文字列入れ
1263
1264
```
1265
$ seq 2 | (echo 'Header'; cat; echo 'Footer')
1266
Header
1267
1
1268
2
1269
Footer
1270
```
1271
1272
```
1273
$ seq 5 | (echo 'obase=2'; cat) | bc
1274
1
1275
10
1276
11
1277
100
1278
101
1279
```
1280
1281
### ファイル入れ
1282
1283
"-"が標準入力のこと
1284
1285
```
1286
$ seq 11 12 | cat data -
1287
1
1288
2
1289
11
1290
12
1291
```
1292
1293
## パイプで渡したコマンドの終了ステータスを得る
1294
1295
```
1296
$ cat test.txt |cat|cat|cat|cat|cat
1297
$ echo ${PIPESTATUS[@]}
1298
0 0 0 0 0 0
1299
```
1300
1301
## bashでパイプで受け取った値を自動エスケープして出力する
1302
1303
俺的備忘録 〜なんかいろいろ〜 - bashでパイプで受け取った値を自動エスケープして出力する
1304
https://orebibou.com/2017/07/bash%e3%81%a7%e3%83%91%e3%82%a4%e3%83%97%e3%81%a7%e5%8f%97%e3%81%91%e5%8f%96%e3%81%a3%e3%81%9f%e5%80%a4%e3%82%92%e8%87%aa%e5%8b%95%e3%82%a8%e3%82%b9%e3%82%b1%e3%83%bc%e3%83%97%e3%81%97%e3%81%a6/
1305
1306
## echo、printfでパイプから受けた値を出力する
1307
1308
俺的備忘録 〜なんかいろいろ〜 - echo、printfでパイプから受けた値を出力する
1309
https://orebibou.com/2017/07/echo%e3%80%81printf%e3%81%a7%e3%83%91%e3%82%a4%e3%83%97%e3%81%8b%e3%82%89%e5%8f%97%e3%81%91%e3%81%9f%e5%80%a4%e3%82%92%e5%87%ba%e5%8a%9b%e3%81%99%e3%82%8b/
1310
1311
## サロゲートペアやUnicode結合文字を考慮して文字単位に分解する
1312
1313
NG
1314
1315
```
1316
$ echo そのチェㇷ゚は𩸽🇯🇵 | grep -o .|tr '\n' '/'
1317
そ/の/チ/ェ/ㇷ/゚/は/𩸽/🇯/🇵
1318
```
1319
1320
OK
1321
1322
```
1323
$ ruby -e 'puts "そのチェㇷ゚は𩸽🇯🇵".scan(/\X/).join("/")'
1324
そ/の/チ/ェ/ㇷ゚/は/𩸽/🇯🇵
1325
```
1326
1327
1328
1329
1330
1331
1332
1333
1334
# awk KnowHow
1335
1336
AWK 一行野郎百裂拳 - 日本 GNU AWK ユーザー会 - No-ip.org
1337
http://gauc.no-ip.org/awk-users-jp/material/100_one_liners_20131223.pdf
1338
1339
> 神
1340
1341
## 特定の N 行を表示する
1342
1343
```
1344
$ awk 'NR==N'
1345
```
1346
1347
## 空行を削除する
1348
1349
```
1350
$ awk 'NF'
1351
$ awk '$0'
1352
$ awk '/./'
1353
```
1354
1355
## 文字数をカウントする(wc -c)
1356
1357
```
1358
$ awk '{n+=length($0)} END{print n}'
1359
```
1360
1361
## 単語数をカウントする(wc -w)
1362
1363
```
1364
$ awk '{n+=NF} END{print n}'
1365
```
1366
1367
## 行数をカウントする(wc -l)
1368
1369
```
1370
$ awk 'END{print NR}'
1371
```
1372
1373
## 行末の空白やタブを削除する
1374
1375
```
1376
$ awk '{sub(/[ \t]+$/, "")}1'
1377
```
1378
1379
## Unix の改行コードに変換する
1380
1381
```
1382
$ awk 'sub(/\r$/,"")'
1383
```
1384
1385
## Windows の改行コードに変換する
1386
1387
```
1388
$ awk 'sub(/$/,"\r")'
1389
```
1390
1391
## 逆順出力をする(tac)
1392
1393
```
1394
$ awk '{a[i++]=$0} END{for(j=i-1; j>=0;) print a[j--]}'
1395
```
1396
1397
## 重複するレコードを削除する(uniq)
1398
1399
```
1400
$ awk '!a[$0]++'
1401
```
1402
1403
## ソートしないで重複行を削除する
1404
1405
```
1406
awk '!a[$0]++' FILE
1407
```
1408
1409
## 行番号を付ける(nl)
1410
1411
```
1412
$ awk '$0 = NR OFS $0'
1413
```
1414
1415
## 標準出力にそのまま出力する(cat -)
1416
1417
```
1418
$ awk '1'
1419
```
1420
1421
## 正規表現にマッチした行を表示する(grep)
1422
1423
```
1424
$ awk '/hogehoge/'
1425
```
1426
1427
## 正規表現にマッチしない行を表示する(grep -v)
1428
1429
```
1430
$ awk '! /hogehoge/'
1431
```
1432
1433
## コメント行を削除する
1434
1435
```
1436
$ awk '! /^#/'
1437
```
1438
1439
## C言語のように複数行にまたがったコメント行を削除する
1440
1441
/* と */ に囲まれた行の場合
1442
1443
```
1444
$ cat file | awk '/\/\*/, /\*\//{next}{print}'
1445
```
1446
1447
## 指定行から指定行までを表示する
1448
1449
```
1450
$ awk 'NR==10,NR==20'
1451
```
1452
1453
## 偶数行を表示する
1454
1455
```
1456
$ awk 'NR%2==0'
1457
```
1458
1459
## 奇数行を表示する
1460
1461
```
1462
$ awk 'NR%2'
1463
```
1464
1465
## 特定のフィールド数を持つ行のみを抜き出す
1466
1467
```
1468
$ cat file
1469
りんご 100円 192個
1470
ばなな 170円 210個
1471
爽健美茶 150円
1472
グラタン ソース マカロニ チーズ じゃがいも
1473
$ cat file | awk 'NF>=2 && NF<=3'
1474
りんご 100円 192個
1475
ばなな 170円 210個
1476
爽健美茶 150円
1477
```
1478
1479
## awkで\[\]\(カギカッコ\)内の値に応じて行を抽出する
1480
1481
```
1482
$ awk -F '[][]' '$4 >= 〇〇' ログファイルPATH
1483
```
1484
1485
1486
1487
```
1488
$ cat log.txt
1489
abc [31/Oct/2015:20:36:51 +0900] ghi [20]
1490
jkl [31/Oct/2015:20:36:55 +0900] pqr [0]
1491
stu [31/Oct/2015:20:37:00 +0900] yz  [40]
1492
000 [31/Oct/2015:20:37:05 +0900] ghi [5]
1493
$ awk -F '[][]' '$4 >= 20' log.txt
1494
abc [31/Oct/2015:20:36:51 +0900] ghi [20]
1495
stu [31/Oct/2015:20:37:00 +0900] yz  [40]
1496
```
1497
1498
## 異なるデミリタを指定して、要素を取り出す
1499
1500
```
1501
$ cat log.txt
1502
abc [31/Oct/2015:20:36:51 +0900] ghi [20]
1503
jkl [31/Oct/2015:20:36:55 +0900] pqr [0]
1504
stu [31/Oct/2015:20:37:00 +0900] yz  [40]
1505
000 [31/Oct/2015:20:37:05 +0900] ghi [5]
1506
$ awk -F '[][]' '{print $1}' log.txt
1507
abc 
1508
jkl 
1509
stu 
1510
000 
1511
$ awk -F '[][]' '{print $2}' log.txt
1512
31/Oct/2015:20:36:51 +0900
1513
31/Oct/2015:20:36:55 +0900
1514
31/Oct/2015:20:37:00 +0900
1515
31/Oct/2015:20:37:05 +0900
1516
$ awk -F '[][]' '{print $3}' log.txt
1517
 ghi 
1518
 pqr 
1519
 yz  
1520
 ghi 
1521
$ awk -F '[][]' '{print $4}' log.txt
1522
20
1523
0
1524
40
1525
5
1526
```
1527
1528
## awkの編集結果をファイルにリダイレクトで出力して保存する
1529
1530
awkでリダイレクトを行う場合、たとえば「tail -F」などと組み合わせて利用する場合、単純に「>」で指定してもリダイレクトが行われない場合がある。
1531
1532
* 例:tail -F で「/work/test」というファイルを常時監視し、その内容に日付を付け足して「/work/test_log」ファイルに出力しようとしている。
1533
1534
```
1535
$ tail -F /work/test | awk '{ print strftime("%Y/%m/%d %H:%M:%S") " " $0 }' > /work/test_log
1536
```
1537
1538
tail -Fとawkを組み合わせてファイルに出力する場合、以下のようにリダイレクトの前に「{ system (" ")}」と記述する必要がある。
1539
1540
```
1541
$ tail -F /work/test | awk '{ print strftime("%Y/%m/%d %H:%M:%S") " " $0 } { system (" ") }' > /work/test_log
1542
```
1543
1544
## Excelのフィルタのように、ファイルから〇〇以上、〇〇以下で行を抽出する
1545
1546
```
1547
$ awk '列 >= 条件 && 列 <= 条件' 対象ファイル
1548
$ awk '列 == 条件' 対象ファイル
1549
$ awk '列 ~ /条件/ 対象ファイル'
1550
```
1551
1552
```
1553
$ cat test.txt 
1554
1 abc 10
1555
2 def 15
1556
3 ghi 0
1557
$ awk '$3 >=5 && $3 <=10' test.txt
1558
1 abc 10
1559
$ awk '$2=="def"' test.txt
1560
2 def 15
1561
$ awk '$2 ~ /abc|ghi/' test.txt
1562
1 abc 10
1563
3 ghi 0
1564
```
1565
1566
1567
## ◯◯時からXX時までの間のログを抽出
1568
1569
```
1570
$ awk -F - '"Apr  5 14:30:00" < $1 && $1 <= "Apr  5 15:00:00"' /var/log/messages
1571
```
1572
1573
## grepのように行を抽出
1574
1575
```
1576
$ awk '/文字列/' 対象ファイル
1577
```
1578
1579
## 任意の行を抽出
1580
1581
```
1582
$ awk 'NR==行' 対象ファイル
1583
$ awk 'NR==最初の行,NR==終わりの行' 対象ファイル
1584
```
1585
1586
## 文字列で範囲を指定して出力
1587
1588
```
1589
$ awk '/任意の開始文字列/,/任意の終了文字列/' 対象ファイル
1590
```
1591
1592
例えば、ファイル2カラム目の「00:00:02」~「00:00:04」までを抽出する場合
1593
1594
```
1595
$ awk '$2 >= "00:00:02" && "00:00:04" >= $2' /tmp/sample.log
1596
```
1597
1598
複数条件(1行目、文字列XXを含む行を抽出とか)で抽出する場合は、awk内でifを使用できる。
1599
1600
```
1601
$ awk '{if(条件1||条件2) print}' 対象ファイル # or条件
1602
$ awk '{if(条件1&&条件2) print}' 対象ファイル # and条件
1603
```
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
# sed KnowHow
1614
1615
## 基本的な使い方
1616
1617
```
1618
$ sed 's/置換前文字列/置換後文字列/g' ファイルPATH
1619
$ コマンド | sed 's/置換前文字列/置換後文字列/g'
1620
```
1621
1622
## ◯行目~◯行目にある特定の文字列を置換する場合
1623
1624
```
1625
$ sed '4,8s/line/gyou/g' test.txt
1626
```
1627
1628
## 特定の文字列を含む行のみ置換する場合
1629
1630
```
1631
$ sed '/検索文字列/s/置換前文字列/置換後文字列/g'
1632
```
1633
1634
## その行に表示される◯番目の文字列を置換する
1635
1636
```
1637
$ sed 's/置換前文字列/置換後文字列/何文字目か'
1638
```
1639
1640
## マッチした文字列を再利用する
1641
1642
1個だけと複数指定可能な2つの方法がある
1643
1644
### 1個だけの方法
1645
1646
置換後文字列の所に&を書くと、その部分がマッチした文字列に置き換わる。
1647
1648
~~~
1649
$ echo "abc def hij klm" |sed -e 's/a[a-z]c/XXX & XXX/g'
1650
XXX abc XXX def hij klm
1651
~~~
1652
1653
### 複数指定可能な方法
1654
1655
\\( と \\) で囲んだものがマッチした場合、順番に \1 \2 \3 と指定できる。
1656
1657
~~~
1658
$ echo "abc def hij klm" |sed -e 's/^\([a-z][a-z][a-z]\) \(d[a-z][a-z]\) \([a-z][a-z][a-z]\) \([a-z][a-z][a-z]\)/XXX \4 \3 \2 \1 XXX/g'
1659
XXX klm hij def abc XXX
1660
~~~
1661
1662
## 指定した行番号の箇所に行を挿入する
1663
1664
```
1665
$ sed '◯i 挿入する行'
1666
$ sed '4i testline' test.txt
1667
```
1668
1669
## 指定した行の後ろに行を挿入する
1670
1671
```
1672
$ sed '◯a 挿入する行'
1673
$ sed '4a testline' test.txt
1674
```
1675
1676
## 指定した複数の各行の前、後ろに行を挿入する
1677
1678
```
1679
$ sed '◯,◯i 挿入する行' #前に挿入する場合
1680
$ sed '◯,◯a 挿入する行' #後に挿入する場合
1681
```
1682
1683
## 指定したキーワードを持つ行の前・後に行を挿入する
1684
1685
```
1686
$ sed '/キーワード/i 挿入する行' #前に挿入する場合
1687
$ sed '/キーワード/a 挿入する行' #後に挿入する場
1688
```
1689
1690
## ◯行目~◯行目を削除する
1691
1692
```
1693
$ sed '◯,◯d'
1694
$ sed '1,4d' test.txt
1695
```
1696
1697
## 決まったキーワードを持つ行を除外する
1698
1699
```
1700
$ sed '/キーワード/d'
1701
$ sed '/line2/d' test.txt
1702
```
1703
1704
## ◯行目の内容を上書きする
1705
1706
```
1707
$ sed '◯c 置き換え後の行'
1708
$ sed '4c testline' test.txt
1709
```
1710
1711
## 特定のキーワードを持つ行を上書きする
1712
1713
```
1714
$ sed '/キーワード/c 置き換え後の行'
1715
$ sed '/line3/c testline' test.txt
1716
```
1717
1718
## ファイルの内容を上書きする
1719
1720
```
1721
$ sed -i '置換条件' ファイルPATH
1722
$ sed 's/line 1/line #/g' test.txt
1723
```
1724
1725
## 複数の置換条件を適用する
1726
1727
```
1728
$ sed -e '置換条件' -e '置換条件' ...
1729
$ sed -e 's/line/gyou/g' -e '5c aaaaaaa' test.txt
1730
```
1731
1732
## ファイルに書いた置換条件を読み込む
1733
1734
```
1735
$ sed -f スクリプトファイルPATH
1736
$ cat /root/sed_script
1737
s/line/gyou/g
1738
5c aaaaaaa
1739
$ sed -f ./sed_script test.txt
1740
```
1741
1742
## 小文字→大文字の変換をする
1743
1744
```
1745
$ sed 's/\(.*\)/\U\1/'
1746
$ sed 's/\(.*\)/\U\1/' test.txt
1747
```
1748
1749
## 大文字→小文字の変換をする
1750
1751
```
1752
$ sed 's/\(.*\)/\L\1/'
1753
$ sed 's/\(.*\)/\L\1/' test.txt
1754
```
1755
1756
## ダブルコーテーション、シングルコーテーションに囲まれた文字列を抽出する
1757
1758
~~~
1759
$ sed 's/^.*"\(.*\)".*$/\1/' # ダブルクォーテーションの場合
1760
$ sed "s/^.*'\(.*\)'.*$/\1/" # シングルクォーテーションの場合
1761
~~~
1762
1763
ちな、grepやawkでもできる
1764
1765
~~~
1766
$ grep -Po '(?<=")[^",]+(?=")' # ダブルクォーテーション
1767
$ grep -Po "(?<=')[^',]+(?=')" # シングルクォーテーション
1768
$ awk -F'['\''"]' '{print $2}'
1769
~~~
1770
1771
## ダブルクォーテーションで囲まれた文字列に対して処理を行う
1772
1773
```
1774
$ sed 's/"\([^"]*\)"/"置換後の値"/' 対象のファイルPATH
1775
$ sed 's/"\([^"]*\)"/"replace"/' test.txt
1776
```
1777
1778
## シングルクォーテーションで囲まれた文字列に対して処理を行う
1779
1780
```
1781
$ sed 's/"\([^"]*\)"/"置換後の値"/' 対象のファイルPATH
1782
$  sed "s/'\([^']*\)'/'replace'/" test.txt
1783
```
1784
1785
## メールアドレスを『○○○@●●●●●』というようにマスキング置換する
1786
1787
```
1788
$ sed "s/[^@ ]*@[^@]*\.[^@ ]*/○○○@●●●●●/g" ファイルPATH
1789
```
1790
1791
## sedで行頭の置換を指定する
1792
1793
```
1794
$ sed 's/^置換前文字列/置換後文字列/g' ファイルPATH
1795
$ sed 's/^test/aaaa/g' test.txt
1796
```
1797
1798
## sedで行頭以外の置換を指定する
1799
1800
```
1801
$ sed 's/\([^^]\)置換前文字列/置換後文字列/g' ファイルPATH
1802
$ sed 's/\([^^]\)test/aaaa/g' test.txt
1803
```
1804
1805
## 指定したディレクトリ内のファイルを再帰的に置換する
1806
1807
```
1808
$ sed 's/置換前/置換後/g' $(find 対象のフォルダPATH -type f)
1809
```
1810
1811
## 特定の文字列~文字列間を置換する
1812
1813
```
1814
$ sed '/文字列(開始)/,/文字列(終了)/s/○○○/●●●/g' 対象のファイルPATH
1815
$ sed '/line2/,/line3/s/test/aaaa/g' test.txt  # line2とline3という文字の間にあるtestをaaaaに置換
1816
$ sed '/line2/,/line3/caaaa' test.txt          # line2がある行とline3がある行、及びその間の行をaaaaに入れ替え
1817
```
1818
1819
## 日本語(マルチバイト文字)のみを置換する
1820
1821
```
1822
$ LANG=C sed 's/[\x80-\xFF]//g' ファイルPATH
1823
$ sed 's/[\x80-\xFF]/●/g' test.txt
1824
```
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
# Other Command KnowHow
1838
1839
## grep
1840
1841
### or検索
1842
1843
```
1844
$ grep -e 検索したい文字列1 -e 検索したい文字列2 検索したいテキストファイル
1845
```
1846
1847
### 大文字・小文字を区別しない
1848
1849
```
1850
$ grep -i 検索したい文字列 検索したいテキストファイル
1851
```
1852
1853
### 検索にヒットする前後の行を出力
1854
1855
検索にヒットした前の行を出力する場合
1856
1857
```
1858
$ grep 検索したい文字列 -B 出力したい行数 検索したいテキストファイル
1859
```
1860
1861
検索にヒットした後の行を出力する場合
1862
1863
```
1864
$ grep 検索したい文字列 -A 出力したい行数 検索したいテキストファイル
1865
```
1866
1867
前後の行を同時に出力したい場合は、Cオプションを付与する。
1868
1869
```
1870
$ grep 検索したい文字列 -C 出力したい行数 検索したいテキストファイル
1871
```
1872
1873
### 検索にヒットする行数を取得する
1874
1875
```
1876
$ grep -c 検索したい文字列 検索したいテキストファイル
1877
```
1878
1879
### ファイルの行番号を出力する
1880
1881
```
1882
$ grep -n 検索したい文字列 検索したいテキストファイル
1883
```
1884
1885
### 単語で検索する
1886
1887
例えばadで検索するとaddressやmadといった、別の意味を持つ単語も引っかかってしまうので
1888
1889
```
1890
$ grep -w 検索したい文字列 検索したいファイル
1891
```
1892
1893
### 複数のキーワードをパターン化したファイルを読込み、合致した行を出力する
1894
1895
```
1896
$ grep -f 検索パターンを記述したファイル 検索したいファイル
1897
```
1898
1899
### 検索キーワードを持つファイルのリストを取得する
1900
1901
```
1902
$ grep -l 検索パターンを記述したファイル 検索したいフォルダ/*
1903
```
1904
1905
## find
1906
1907
ここ読んでよく勉強すること!!1
1908
1909
俺的備忘録 〜なんかいろいろ〜 - findコマンドで覚えておきたい使い方12個
1910
http://orebibou.com/2015/03/find%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%A7%E8%A6%9A%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84%E4%BD%BF%E3%81%84%E6%96%B912%E5%80%8B/
1911
1912
## date
1913
1914
### 今日を基準として、任意の時間経過された日時を求める
1915
1916
```
1917
$ date
1918
2015年 10月 31日 土曜日 21:29:13 JST
1919
$ date -d '-1day'
1920
2015年 10月 30日 金曜日 21:29:05 JST
1921
$ date -d '1day'
1922
2015年 11月  1日 日曜日 21:29:08 JST
1923
$ date -d '1hour'
1924
2015年 10月 31日 土曜日 22:31:33 JST
1925
$ date -d '1month'
1926
2015年 12月  1日 火曜日 21:31:38 JST
1927
$ date -d '1year'
1928
2016年 10月 31日 月曜日 21:31:42 JST
1929
```
1930
1931
### 来月の月初、3ヶ月先の月末日付を求める
1932
1933
```
1934
$ date +%Y/%m/%d
1935
2015/10/31
1936
$ date +%Y/%m/01
1937
2015/10/01
1938
$ date +%Y/%m/01 -d '+1 month'
1939
2015/12/01
1940
$ date +%Y/%m/%d -d "-1day `date +%Y%m01 -d '+4 month'`"
1941
2016/02/29
1942
```
1943
1944
### 閏年の判断
1945
1946
閏年じゃない場合はエラーになる。
1947
1948
```
1949
$ date -d 2012-02-29 +%Y
1950
2012
1951
$ date -d 2013-02-29 +%Y
1952
date: `2013-02-29' は無効な日付です
1953
```
1954
1955
-f-とすれば標準入力から複数の日付を受け付けてくれる。
1956
こうすれば閏年だけ抜き出せる。
1957
1958
```
1959
$ seq 1900 2400 | sed 's/$/-02-29/' | date -f- +%Y 2> /dev/null
1960
```
1961
1962
1963
1964
1965
## sort
1966
1967
### バイト数(KB、MB、GB etc…)を並び替えする
1968
1969
```
1970
$ du -h /home | sort -hr
1971
```
1972
1973
1974
## uniq
1975
1976
### 重複した行・重複していない行だけを表示させる
1977
1978
重複している行のみを出力させる場合は「-d」を、重複のない(ユニークな)行をのみを出力させる場合は「-u」オプションを付与する。
1979
1980
```
1981
$ cat test.txt | uniq -d
1982
$ cat test.txt | uniq -u
1983
```
1984
1985
## watch
1986
1987
### 実行コマンドがエラーになった場合、watchコマンドを終了する
1988
1989
```
1990
$ watch -e 実行コマンド
1991
```
1992
1993
なお、「-e」の場合はコマンドの実行は停止するが何かキーを押下するまで画面はそのままとなる。
1994
1995
### 実行コマンドに変化があった場合、watchコマンドを終了する
1996
1997
```
1998
$ watch -g 実行コマンド
1999
```
2000
2001
## xargs
2002
2003
### 基本的な使い方
2004
2005
以下のようにパイプでつなぐことで前のコマンド(コマンド1)で取得した値(標準出力)を利用してxargsで指定した別のコマンド(コマンド2)に引数として渡して実行させる事ができるコマンド
2006
2007
```
2008
$ コマンド1 | xargs コマンド2
2009
```
2010
2011
### 実行されるコマンド内容を表示させる
2012
2013
```
2014
$ コマンド1 | xargs -t コマンド2
2015
```
2016
2017
### コマンドライン一行に引数をいくつ渡すか指定する
2018
2019
```
2020
$ コマンド1 | xargs -n 引数の数 コマンド2
2021
```
2022
2023
### 引数の値を明示的に利用する
2024
2025
```
2026
$ コマンド1 | xargs -I{} コマンド2 {}
2027
```
2028
2029
例えば「/work」フォルダ配下にあるファイルに対し、元のファイル名の後ろに「.bk」という文字列を付け足してコピーする場合
2030
2031
```
2032
$ find /work -type f | xargs -t -I{} cp {} {}.bk
2033
```
2034
2035
### コマンドの実行をするかどうか確認する
2036
2037
```
2038
$ コマンド1 | xargs -p コマンド2
2039
```
2040
2041
### 複数プロセスを同時に実行させる
2042
2043
```
2044
$ コマンド1 | xargs -P 最大プロセス数 コマンド2
2045
```
2046
2047
### 引数の区切り文字を指定する
2048
2049
```
2050
$ コマンド1 | xargs -d区切り文字 コマンド2
2051
```
2052
2053
## eval
2054
2055
### 変数の2重展開
2056
2057
```
2058
#!/bin/sh
2059
# 変数 VARに値が入力されている
2060
VAR="test"
2061
 
2062
# 変数 EVAL_VARに、変数名である「VAR」という文字列を入力
2063
EVAL_VAR="VAR"
2064
 
2065
# 変数 EVAL_VARを呼び出す
2066
# echo $EVAL_VAR
2067
eval echo '$'$EVAL_VAL
2068
```
2069
2070
### 変数が配列の場合の2重展開
2071
2072
```
2073
#!/bin/sh
2074
# 変数「VAL」を配列として値を代入していく
2075
VAL[0]="line 1"
2076
VAL[1]="line 2"
2077
VAL[2]="line 3"
2078
 
2079
# 変数 EVAL_VALに、変数名である「VAL」という文字列を入力
2080
EVAL_VAL="VAL"
2081
 
2082
# 変数 EVAL_VALを呼び出す
2083
eval echo '$'$EVAL_VAL
2084
 
2085
# 変数 EVAL_VALを配列として全行呼び出す
2086
eval echo '${'$EVAL_VAL'[@]}'
2087
 
2088
# 変数 EVAL_VALを配列として[1]を呼び出す
2089
eval echo '${'$EVAL_VAL'[1]}'
2090
```
2091
2092
## ssh
2093
2094
### ローカルのbashの設定使ってssh接続
2095
2096
```
2097
$ ssh -t user@host 'bash --rcfile <( echo ' $(cat ~/.bashrc ~/.bash_function_etc... | base64 ) ' | base64 -d)'
2098
```
2099
2100
>環境によってはbase64に-w0オプションが必要かも?
2101
2102
### Dockerにローカルのbashrcやvimrcを使って接続
2103
2104
```
2105
$ docker run --rm -it コンテナ bash -c '/bin/bash --rcfile <(echo -e '$(cat ~/.bashrc ~/.bash_function_etc... |base64)'|base64 -d)'
2106
```
2107
2108
今のセッションの環境変数をそのまま使う場合は
2109
2110
```
2111
$ docker run --rm -it コンテナ bash -c '/bin/bash --rcfile <(echo -e '$(cat <(set) <(alias)|base64 -w0)'|base64 -d)'
2112
```
2113
2114
### ローカルにあるスクリプトを配布せずにリモート先で実行させる
2115
2116
```
2117
$ ssh リモート先のユーザ名@リモート先のホスト名(IPアドレス) 'sh ' < 実行させたいスクリプトのパス
2118
$ 
2119
```
2120
2121
### 直接リモート先のマシン上でコマンドを用いたsedを行わせる
2122
2123
```
2124
$ sed ユーザ名@リモートホスト sed s/aaaaa/`hostname`/g 対象ファイル   # ローカル側でhostnameが実行される
2125
$ sed ユーザ名@リモートホスト 'sed s/aaaaa/`hostname`/g' 対象ファイル # リモート側でhostnameが実行される
2126
```
2127
2128
### リモート側のファイルにローカルファイルの内容を追記する方法
2129
2130
```
2131
$ ssh ユーザ名@リモートホスト "cat >> /追記するリモートファイルのパス" < /追記させるローカルファイルのパス
2132
$ ssh test@192.168.0.240 "cat >> /tmp/test_remote.text" < test_local.txt
2133
```
2134
2135
ローカル側のコマンドの実行結果(ローカル側のファイルに対し、sedを実行した後の内容を追記するなど)を追記する場合は、以下のようにする。
2136
2137
```
2138
$ ローカル側で標準出力を行うコマンド | ssh ユーザ名@リモートホスト "cat >> /追記するリモートファイルのパス"
2139
$ sed 's/test/AAAA/g' text_local.txt | ssh test@192.168.0.240 "
2140
```
2141
2142
### ssh経由でディレクトリにあるファイル一覧をdiffする
2143
2144
公開鍵認証じゃないとダメかもしれない
2145
2146
```
2147
$ diff <(ssh ユーザ名@ホスト名 'find /確認するPATH -type f | sort') <(find /確認するPATH -type f | sort)
2148
$ diff <(ssh test@192.168.0.240 find /work -type f | sort) <(find /work -type f | sort)
2149
```
2150
2151
rsyncコマンドで代用できる
2152
2153
```
2154
$ rsync --checksum --dry-run -rvce "ssh -p ポート番号" ユーザ名@ホスト名:/対象ディレクトリ /対象ディレクトリ
2155
```
2156
2157
### ssh経由でファイル内容をdiffする
2158
2159
```
2160
$ diff <(ssh ユーザ名@ホスト名 'cd /確認するPATH; grep -Rn "" ./ | sort') <(cd /確認するPATH; grep -Rn "" ./ | sort)
2161
$ diff <(ssh test@192.168.0.240 'cd /work;grep -Rn "" ./ | sort') <(cd /work;grep -Rn "" ./ | sort)
2162
```
2163
2164
### ローカルでファイル・フォルダを圧縮し、リモートでアーカイブファイルとして保持させる
2165
2166
```
2167
$ tar zcvf - /アーカイブ化したいディレクトリのパス | ssh ユーザ名@リモートホスト "cat > /リモート側で作成するアーカイブ・ファイルのパス
2168
$ tar zcvf - /wort_test | ssh test@192.168.0.240 "cat > /wort_test.tar.gz"
2169
```
2170
2171
### ローカルのアーカイブファイルをリモートで解凍する
2172
2173
```
2174
$ ssh ユーザ名@リモートホスト "tar zxvf -C リモート側で展開させたいフォルダ -" < /リモート側で解凍させたいアーカイブファイルのパス
2175
$ ssh test@192.168.0.240 "tar zxvf - -C /test1234" < test.tar.gz
2176
```
2177
2178
### リモートでファイル・フォルダを圧縮し、ローカルでアーカイブファイルとして保持させる
2179
2180
```
2181
$ ssh ユーザ名@リモートホスト "tar -cf - /アーカイブ化したいディレクトリのパス" | gzip > /ローカル側で作成するアーカイブ・ファイルのパス
2182
$ ssh test@192.168.0.240 "tar -cf - /work/test" | gzip > /root/test.tar.gz
2183
```
2184
2185
### リモートのアーカイブファイルをローカルで解凍する
2186
2187
```
2188
$ ssh ユーザ名@リモートホスト "cat /ローカル側で解凍させたいアーカイブファイル" | tar zxvf - -C ローカル側で展開させたいフォルダ
2189
$ ssh test@192.168.0.240 "cat /work.tar.gz" | tar zxvf - -C /test/
2190
```
2191
2192
### 踏み台サーバ経由でログインを行う
2193
2194
```
2195
$ ssh ユーザ名@接続先のホスト名(IPアドレス) -o 'ProxyCommand ssh 踏み台サーバのユーザ@踏み台サーバのホスト名 nc %h %p'
2196
$ ssh test1@192.168.0.2-o 'ProxyCommand ssh test2@192.168.0.3 nc %h %p'
2197
```
2198
2199
### ssh接続時に直接コマンドを実行する
2200
2201
```
2202
$ ssh ユーザ名@接続先のホスト名(IPアドレス) '接続先で実行させるコマンド'
2203
```
2204
2205
### sshでsuによるユーザ切り替え時に自動でパスワード入力をさせる
2206
2207
```
2208
$ ssh login@host "su - user -c 'command' << EOF
2209
password
2210
EOF"
2211
```
2212
2213
## dd
2214
2215
### バイナリファイルでのcutコマンド相当
2216
2217
```
2218
$ cat file | dd bs=1 skip=100
2219
```
2220
2221
### バイナリファイルでのheadコマンド相当
2222
2223
固定長レコード限定
2224
2225
```
2226
$ dd bs=[レコード長] count=[抜き出したい行数] skip=[読み飛ばしたい行数] if=[入力ファイル] of=[出力ファイル]
2227
```
2228
2229
2230
2231
2232
2233
2234
# シェル芸
2235
2236
UPS友の会
2237
https://www.usptomo.com/
2238
2239
上田ブログ
2240
https://blog.ueda.asia/
2241
2242
シェル芸人達
2243
https://daichkr.hatelabo.jp/collection/960679194075891200
2244
2245
日々是迷歩
2246
http://papiro.hatenablog.jp/
2247
2248
slideshare シェル芸
2249
http://www.slideshare.net/search/slideshow?searchfrom=header&q=%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8&ud=&ft=&lang=&sort=
2250
2251
## Open usp Tukubai
2252
2253
基本的に、以下からダウンロードして展開すれば使える
2254
https://uec.usp-lab.com/TUKUBAI/CGI/TUKUBAI.CGI?POMPA=DOWNLOAD
2255
2256
コマンドの説明は以下
2257
https://uec.usp-lab.com/TUKUBAI_MAN/CGI/TUKUBAI_MAN.CGI?POMPA=LIST
2258
2259
Github - ShellShoccar-jpn/Parsrs
2260
https://github.com/ShellShoccar-jpn/Parsrs
2261
2262
## egzact
2263
2264
シェルの弱点を補おう!"まさに"なCLIツール、egzact
2265
http://qiita.com/greymd/items/3515869d9ed2a1a61a49 https://github.com/greymd/egzact
2266
2267
## エクシェル芸
2268
2269
俺的備忘録 〜なんかいろいろ〜 - Excelファイル(~.xls/~.xlsx)をLinuxコンソール上でCSV方式に変換する方法
2270
https://orebibou.com/2016/12/excel%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%ef%bd%9e-xls%ef%bd%9e-xlsx%e3%82%92linux%e3%82%b3%e3%83%b3%e3%82%bd%e3%83%bc%e3%83%ab%e4%b8%8a%e3%81%a7csv%e6%96%b9%e5%bc%8f%e3%81%ab%e5%a4%89%e6%8f%9b/
2271
2272
2273
2274
2275
2276
2277
2278
2279
## ワンライナー
2280
2281
### アクセスログから、接続元IPをカウントし、合計で100回以上アクセスしているIPのみアクセスが多い順に表示する
2282
2283
```
2284
cat /var/log/httpd/access_log* |   awk '/\"GET .*\" 200 / || /\"CONNECT .*\" 200 /   {cnt[$1]+=1};END{for (key in cnt)  {if(cnt[key] > 100)  {print cnt[key],key}}}' |  sort -nr
2285
```
2286
2287
### アクセスログから、リファラなしの閲覧先ドメインをカウントし、合計で100回以上アクセスがあるURLのみアクセスが多い順に表示する
2288
2289
```
2290
cat /var/log/httpd/access_log*  |  awk -F\" '/GET .* 200 / || /CONNECT .* 200 /  {cnt[$2]+=1};END{for (key in cnt)  {if(cnt[key] > 100)  {print cnt[key],key}}}' |  sed -e 's% HTTP/...%%g' | sort -nr
2291
```
2292
2293
2294
2295
# シェル芸化
2296
2297
シェル芸の定義はこうだ。
2298
2299
>マウスも使わず、ソースコードも残さず、GUI ツールを立ち上げる間もなく、あらゆる調査・計算・テキスト処理を CLI 端末へのコマンド入力一撃で終わらすこと。
2300
2301
では、やってみましょう。
2302
全ての手続きを1行に。
2303
2304
## 1行化の基本
2305
2306
```
2307
$ echo "a"
2308
$ echo "b"
2309
$ echo "c"
2310
```
2311
2312
;で区切ることで1行化できる。
2313
2314
```
2315
$ echo "a";echo "b";echo "c"
2316
```
2317
2318
### && の利用
2319
2320
```
2321
$ hoge ; date
2322
-bash: hoge: コマンドが見つかりません
2323
2016年  6月 19日 日曜日 11:01:32 JST
2324
```
2325
2326
&&で区切ると、hogeが正常終了した場合のみ、後続のコマンドを実行する。
2327
正常終了とは、コマンドの復帰値($?)が0の場合を指す。
2328
2329
```
2330
$ hoge && date
2331
-bash: hoge: コマンドが見つかりません
2332
```
2333
2334
これは以下と等価である。
2335
2336
```
2337
#!/bin/bash
2338
2339
hoge
2340
2341
RET=$?
2342
if [ $RET -eq "0" ]
2343
then
2344
  date
2345
else
2346
  exit $RET
2347
fi
2348
```
2349
2350
### || の利用
2351
2352
```
2353
$ hoge ; date
2354
-bash: hoge: コマンドが見つかりません
2355
2016年  6月 19日 日曜日 11:01:32 JST
2356
```
2357
2358
||で区切ると、hogeが異常終了した場合のみ、後続のコマンドを実行する。
2359
異常終了とは、コマンドの復帰値($?)が0以外の場合を指す。
2360
2361
```
2362
$ hoge || date
2363
-bash: hoge: コマンドが見つかりません
2364
2016年  6月 19日 日曜日 11:17:16 JST
2365
```
2366
2367
これは以下と等価である。
2368
2369
```
2370
#!/bin/bash
2371
2372
hoge
2373
2374
RET=$?
2375
if [ $RET -nq "0" ]
2376
then
2377
  date
2378
fi
2379
```
2380
2381
## if文の1行化
2382
2383
これが
2384
2385
```
2386
RET="0"
2387
if [ $RET -eq "0" ]
2388
then
2389
  echo "true"
2390
else
2391
  echo "false"
2392
fi
2393
```
2394
2395
こうじゃ!
2396
2397
```
2398
RET="0";if [ $RET -eq "0" ]; then echo "true"; else echo "false"; fi
2399
```
2400
RETの値を変えれば、分岐されていることを確認できる。
2401
2402
### && , || の利用
2403
2404
以下のように、&& や || を利用することもできます。
2405
2406
```
2407
$ RET="0";[ $RET -eq "1" ] || echo "It work"
2408
It work
2409
$ RET="0";[ $RET -eq "0" ] && echo "It work"
2410
It work
2411
```
2412
2413
## for文の1行化
2414
2415
これが
2416
2417
```
2418
for I in {1..10}
2419
do
2420
  echo $I
2421
done
2422
```
2423
2424
こうじゃ!
2425
2426
```
2427
for I in {1..10} ; do echo $I ; done
2428
```
2429
2430
これでもいけるらしい
2431
2432
~~~
2433
for I in {1..5};{ echo $I;}
2434
for((;;)){ echo 1;sleep 1; } # 無限ループ
2435
~~~
2436
2437
## while文の1行化
2438
2439
これが
2440
2441
```
2442
I=1
2443
while [ $I -le 10 ]
2444
do
2445
  echo $I
2446
  I=$((I+1))
2447
done
2448
```
2449
2450
こうじゃ!
2451
2452
```
2453
I=1; while [ $I -le 10 ]; do echo $I;I=$((I+1)); done
2454
```
2455
2456
## case文の1行化
2457
2458
これが
2459
2460
```
2461
case $I in
2462
  a ) echo "a1"
2463
      echo "a2";;
2464
  b ) echo "b1"
2465
      echo "b2";;
2466
  * ) echo "default";;
2467
esac
2468
```
2469
2470
こうじゃ!
2471
2472
```
2473
case $I in a ) echo "a1"; echo "a2";; b ) echo "b1"; echo "b2";; * ) echo "default";; esac
2474
```
2475
2476
## 関数の1行化
2477
2478
これが
2479
2480
```
2481
funcSample(){
2482
echo "It work"
2483
}
2484
funcSample
2485
```
2486
2487
こうじゃ!
2488
2489
```
2490
funcSample(){ echo "It work"; };funcSample
2491
```
2492
2493
## シェル芸ブブ化
2494
2495
シェルスクリプトをシェル芸化(ワンライナー)するスクリプト
2496
2497
[[シェル芸ブブ化]]
2498
2499
2500
2501
# Test/Lint
2502
2503
POSTD - Bashアプリケーションをテストする
2504
http://postd.cc/bash%e3%82%a2%e3%83%97%e3%83%aa%e3%82%b1%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%82%92%e3%83%86%e3%82%b9%e3%83%88%e3%81%99%e3%82%8b/
2505
2506
ShellCheck - ShellCheck, a static analysis tool for shell scripts
2507
http://www.shellcheck.net/ https://github.com/koalaman/shellcheck
2508
2509
Batsを使ったシェルスクリプトのテスト
2510
https://rcmdnk.com/blog/2019/10/11/computer-github-bash/
2511
2512
pre-commitでShellCheckを使う
2513
https://rcmdnk.com/blog/2023/01/09/computer-shell-python/
2514
2515
AWK commands equivalent to SQL query – Data manipulation
2516
https://subhadip.ca/unixlinux/awk-commands-equivalent-to-sql-query-data-manipulation/4/
2517
2518
>SQLのINNER JOINやLEFT OUTER JOINをawkで実現
2519
2520
シェルスクリプトにxUnitを使ってみる
2521
https://qiita.com/filunK/items/aa067383aaa317594d17
2522
2523
2524
2525
2526
2527
2528
# Memo
2529
2530
## sed
2531
2532
Qiita - sedのパターンスペース・ホールドスペースの動作を図で学ぶ
2533
http://qiita.com/gin_135/items/773fec1343a69c9f90d6
2534
2535
俺的備忘録 〜なんかいろいろ〜 - sedのデバッグやHTML化ができる『sedsed』
2536
https://orebibou.com/2016/11/sed%E3%81%AE%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E3%82%84html%E5%8C%96%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E3%80%8Esedsed%E3%80%8F/
2537
2538
2539
## Misc
2540
2541
Defensive BASH Programming
2542
http://www.kfirlavi.com/blog/2012/11/14/defensive-bash-programming
2543
2544
Perl1行野郎
2545
http://web.archive.org/web/20020203071153/www13.cds.ne.jp/~ohsaru/perl/oneline.html
2546
2547
WICKED COOL SHELL SCRIPTS
2548
http://www.intuitive.com/wicked/wicked-cool-shell-script-library.shtml
2549
2550
Bourne Shell自習テキスト
2551
http://lagendra.s.kanazawa-u.ac.jp/ogurisu/manuals/sh-text/sh/
2552
2553
Qiita - richmikan@github
2554
http://qiita.com/richmikan@github
2555
2556
glot.io - 様々な言語のコードスニペットが共有できるサイト
2557
https://glot.io/
2558
2559
CMD-CHALLENGE - なんかCTFのようなシェル芸勉強サイト!!
2560
https://cmdchallenge.com/
2561
2562
Thanks Driven Life - shellcheck を Docker で実行する
2563
http://gongo.hatenablog.com/entry/2017/03/28/223757
2564
2565
Command Challenge - ★CTFみたい!!★
2566
https://cmdchallenge.com/
2567
2568
explainshell.com - 難しめのシェル芸の解析
2569
https://explainshell.com/
2570
2571
Yakst - 私が他人のシェルスクリプトから学んだこと
2572
https://yakst.com/ja/posts/31
2573
2574
Qiita - bashの組込みコマンド自作によるスクリプトの高速化
2575
https://qiita.com/satoru_takeuchi/items/7d424fa5ef1e33ace4df
2576
2577
Qiita - ネットワーク越しでパイプしたり、あらゆるデバイス間でデータ転送したい!
2578
https://qiita.com/nwtgck/items/78309fc529da7776cba0
2579
2580
ble - Bashを動的にシンタックスハイライトする
2581
https://github.com/akinomyoga/ble.sh
2582
2583
if 文と test コマンド | UNIX & Linux コマンド・シェルスクリプト リファレンス
2584
https://shellscript.sunone.me/if_and_test.html
2585
2586
bashスクリプティング研修の資料を公開します
2587
https://www.m3tech.blog/entry/2018/08/21/bash-scripting
2588
2589
set -eのもとで特定のコマンドの終了ステータスを変数に入れるシェルスクリプトのスニペット
2590
https://gfx.hatenablog.com/entry/2021/12/15/153937
2591
2592
bash スクリプトの実行中上書き動作について
2593
https://zenn.dev/mattn/articles/5af86b61004bdc
2594
2595
pure sh bible (📖 A collection of pure POSIX sh alternatives to external processes). - コマンドを使わずpure bashであれやこれやする一覧
2596
https://github.com/dylanaraps/pure-bash-bible#get-the-directory-name-of-a-file-path
2597
2598
shell.how - インタラクティブにコマンド内容やオプションを解説してくれる
2599
https://www.shell.how/
2600
2601
なぜシェルスクリプトで高度なデータ管理にSQLiteを使うべきなのか? ~ UNIX/POSIXコマンドの欠点をSQLで解決する
2602
https://qiita.com/ko1nksm/items/33ab7ced0f9f8acdff28
2603
2604
onceupon/Bash-Oneliner
2605
https://github.com/onceupon/Bash-Oneliner
2606
2607
シェルスクリプトの表示を豊かにするgumの使い方
2608
https://dev.classmethod.jp/articles/eetann-gum-suburi/
2609
2610
GoogleのShell Style Guideの邦訳
2611
https://qiita.com/yabeenico/items/72b904d4bb0b6d732a86
2612
2613
シェルスクリプトでgetoptsで解析する引数をポジショナルな引数と混合して使えるようにする
2614
https://rcmdnk.com/blog/2023/11/01/computer-bash/
2615
2616
Bashの文字列で特殊文字を使う方法
2617
https://azisava.sakura.ne.jp/programming/0010.html
2618
2619
シェルスクリプトで関数をそのままサブコマンドとして使う
2620
https://rcmdnk.com/blog/2024/09/08/computer-bash/#google_vignette
2621
2622
改めて整理する、コンソール・ターミナル・仮想コンソール・端末エミュレータ・擬似端末
2623
https://www.kanzennirikaisita.com/posts/what-is-console-terminal-etc
2624
2625
ASCII control characters in my terminal (端末の ASCII 制御文字)
2626
https://jvns.ca/blog/2024/10/31/ascii-control-characters/
2627
2628
yassinebenaid/bunster(シェルスクリプトをバイナリ形式に変換するツール:Go実装にトランスパイル)
2629
https://github.com/yassinebenaid/bunster
2630
2631
2632
2633
# 謝辞
2634
2635
以下のサイトを中心に参考にさせて頂いております。
2636
ありがとうございます。
2637
2638
日々是迷歩
2639
http://papiro.hatenablog.jp/
2640
2641
俺的備忘録 〜なんかいろいろ〜
2642
http://orebibou.com/
2643
2644
Qiita - 実用 awk ワンライナー
2645
http://qiita.com/b4b4r07/items/45d34a434f05aa896d69
2646
2647
SlideShare - 検索:シェル芸
2648
http://www.slideshare.net/search/slideshow?searchfrom=header&q=%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8