シェルの習得中

# シェルの書き方、正規表現、文法を学習のために1つ1つ記述していきます。
* 2月中めどで、だいたい網羅します。
* 何かのお役に立てますと幸いです
* シェルマスターに俺はなる


```sh

```

# はじめに

```sh


#! /bin/bash -
# 冒頭の#!の次の値をプログラムへのパスとする
# オプションが1つ指定できる 例:#! /bin/awk -f
# 行末の「-」 はこの場合、「bashのオプションがこれ以上記述されない」という意味
# 特定のセキュリティ攻撃に対しての防御策となる




# 「--」 はオプションが終わりであることを示す
# 以降の文字列は引数として扱われる
ls -l --
# 結果
total 0
-rw-r--r--  1 t-yamamoto  staff  0  1 27 11:02 pr.txt


```

# printf

```sh




# printfコマンド　"文字列"を表す書式指定子「%s」 #改行「\n」
printf -- "hello world %s %s\n" yama tetsu
# 結果
hello world yama tetsu




# printfコマンド　"正規表現を含む文字列"を表す書式指定子「%b」 "数字"を表す「%d」
printf -- '%b%b%b%b%d\n' "aaa\n" "bbb\n" "ccc\n" "ddd\n" "140"
# 結果
aaa
bbb
ccc
ddd
140




# ダブルコーテなし　\はエスケープ文字とみなされる
printf -- '%b%b%b%b%d\n' aaa\n bbb\n ccc\n ddd\n 140
# 結果
aaanbbbncccndddn140




# コマンドを書いてみる `コマンド`
printf -- '%b %b %b %b %b\n' aaa bbb ccc ddd `mkdir aaa`
# 結果
aaa bbb ccc ddd

  # mkdirは実行された・・・？
  ls -l
  # 結果 実行されていた・・・ (%sでも一緒)
  total 8
  -rw-r--r--  1 t-yamamoto  staff  20  1 27 11:30 pr.txt
  drwxr-xr-x  2 t-yamamoto  staff  68  1 27 11:45 aaa




# \で特殊文字をエスケープできる ``をエスケープしてみる
printf -- '%b %b %b %b %b\n' aaa bbb ccc ddd \`mkdir aaa\`
# 結果
aaa bbb ccc ddd `mkdir
aaa`

  # 空白も特殊文字でした　※空白は引数の区切りとして扱われます
  # aaa\`は、5つ目の引数のあとに、改行\nがあるため、
  # 改行後に新たな行の1つ目の%bに対する引数として出力された



# \で特殊文字をエスケープできる ``と空白をエスケープしてみる
printf -- '%b %b %b %b %b\n' aaa bbb ccc ddd \`mkdir\ aaa\`
# 結果
aaa bbb ccc ddd `mkdir aaa`

 # できた・



# printfコマンド　"数字"を表す「%d」 "%"を"%"でエスケープできる
printf -- '%d %% \n' "140"
# 結果
140 %



# 変数展開1  ダブルコーテに、シングルコーテで呼ばれる$ddd
ddd="ddd"
printf -- "%b" '$ddd\n'
# 結果
$ddd

# 変数展開2    ダブルコーテに、ダブルコーテで呼ばれる$ddd
printf -- "%b" "$ddd\n"
# 結果
ddd

# 変数展開3    シングルコーテに、ダブルコーテで呼ばれる$ddd
printf -- '%b' "$ddd\n"
# 結果
ddd

# 変数展開4    シングルコーテに、シングルコーテで呼ばれる$ddd
printf -- "%b" '$ddd\n'
# 結果
$ddd

# 呼び出し元のコーテーションがダブルかシングルかには関係なく、
# 記述先のコーテーションの変数展開ルールに従うようです




# 書式指定子なし1
printf "$ddd\n"
# 結果
ddd


# 書式指定子なし2
printf '$ddd\n'
# 結果
$ddd


# デフォルトは%bと同じ動きかと




# 1つの書式指定子「%d」(数字を表す書式指定)に、4つの引数
printf '%d\n' 1 2 "3" あ
# 結果
1
2
3
-bash: printf: あ: invalid number
0

# 複数の引数でも、1つの書式指定子で扱える
# もちろん、書式指定に従わないとはじかれる
# なぜか、0とみなされる




# 2つの書式指定子「%d」(数字を表す書式指定)「%s」(文字列を表す書式指定)に、4つの引数を与えてみる
printf '%d %s\n' 1 2 "3" あ
# 結果
1 2
3 あ




# 実験1　　外部出力>
printf '%s\n' "aaaa" "bbbb" "cccc" "dddd" >pr.txt
cat pr.txt
# 結果
aaaa
bbbb
cccc
dddd


# 実験2    改行を削除して読み込み
printf '%s' `cat pr.txt`
# 結果
aaaabbbbccccdddd


# 実験3    外部出力を改行つけて読み込み
printf '%s\n' `cat pr.txt`
# 結果
# 1行ごとに読み込まれて%sに渡されていることがわかる
aaaa
bbbb
cccc
dddd


# 実験4    偶数行を空白区切りで出力
printf '%s %s\n' `cat pr.txt`
# 結果
aaaa bbbb
cccc dddd


# 実験5    変数格納
aaa="printf %b\n `cat pr.txt`"
$aaa
# 結果
aaaa
bbbb
cccc
dddd


# 実験6    変数に入れると少し勝手が変わる　
# 書式指定子をコーテーションでくくれない
# つまり、書式指定子と書式指定子の間に空白が入れられない
# タブの正規表現(\t)で区切る
aaa="printf %b\t%b\n `echo test` `cat pr.txt`"
$aaa
# 結果
test	aaaa
bbbb	cccc
dddd


# 実験7 ,で区切る
aaa="printf %b,%b\n `echo test` `cat pr.txt`"
$aaa
# 結果
test,aaaa
aaa,bbbb
cccc,dddd


# 実験8   #脱線　 実験6の,を空白に置換
$aaa |sed 's#,# #g'
# 結果
test aaaa
bbbb cccc
dddd




```

# tr

```sh

# 事前準備
printf '%s\n' "aaaa" "bbbb" "cccc" "dddd" >t_r_.txt
cat t_r_.txt
# 結果
aaaa
bbbb
cccc
dddd


# tr コマンドで標準入力の文字列から改行コードを除く
tr -d -- '\n' <./t_r_.txt
# 結果
aaaabbbbccccdddd




# tr コマンドで標準入力の文字列の改行をタブに置換
tr -- '\n' '\t' <./t_r_.txt
# 結果
aaaa	bbbb	cccc	dddd




# tr コマンドで標準入力の文字列の"aaaa"以外を"b"に置換
tr -c -- 'aaaa' 'b' <./t_r_.txt
# 結果
aaaabbbbbbbbbbbbbbbb

  # 改行もbに置換される


```

# grep

```sh

# 事前準備
printf '%s\n' "aaaa" "bbbb" "cccc" "dddd" "-aaa" "AAAA" "1111" "2222">gr.txt
cat gr.txt
# 結果
aaaa
bbbb
cccc
dddd
-aaa
AAAA
1111
2222



# grepの使い方と正規表現

# デフォルトでは指定した文字列にマッチしたら表示してくれる
# [[:alnum:]] は、POSIXでのアルファベットと数字の文字クラス
grep -- [[:alnum:]] gr.txt
# 結果
aaaa
bbbb
cccc
dddd
-aaa
AAAA
1111
2222



# -v は指定した文字以外を抽出
grep "bbbb" gr.txt -v --
# 結果
aaaa
cccc
dddd
-aaa
AAAA
1111
2222



# -l はマッチしたファイル名を表示してくれる つまり、できる奴
grep [[:alnum:]] -l ./*.*
# 結果
./gr.txt




# -e はマイナス記号をオプションとみなさない　つまり、親切
grep -e -aaa -- gr.txt
# 結果
-aaa




# -i は大文字小文字を区別しない つまり、おおらか
grep -i -- aaaa gr.txt
# 結果
aaaa
AAAA



# -q は何も表示しない　エラーコードを返す　つまり、冷静
grep -q -- aaaa gr.txt
# 結果
(出力なし)

#エラーコード出力
printf '%b\n' "$?"
# 結果
0




# POSIXでのアルファベットと数字の文字クラス[[:alnum:]]以外
# [[:alpha:]] アルファベット

# [[:blank:]]スペースとタブ

# [[:cntrl:]]制御文字

# [[:digit:]]数字

# [[:xdigit:]]16進数の数字

# [[:graph:]]スペース以外

# [[:lower:]]小文字

# [[:upper:]]大文字

# [[:print:]]印字可能な字

# [[:punct:]]句読点 というか記号

# [[:space:]]空白(を含む)




# ^行頭行末$
grep -i ^aaaa$ gr.txt
# 結果
aaaa
AAAA




# \ は特殊文字の打ち消し
grep \.\* gr.txt
# 結果
aaaa
bbbb
cccc
dddd
-aaa
AAAA
1111
2222
    # cat gr.txtと同じ




# grepは grep -E でegrepと同じEREの正規表現がつかえるようになる(後述)
# オプション無しのgrepでは、 BREの正規表現が使える


# BREの正規表現

# ブラケット表現　任意の一文字にマッチ
grep [abcse*¥] gr.txt
# 結果
aaaa
bbbb
cccc
-aaa




# 1 2 3を含む行にマッチ
grep [1-3] gr.txt
# 結果
1111
2222




# a b cを含む行にマッチ ※ロケール設定に依存
grep [a-c] gr.txt
# 結果
aaaa
bbbb
cccc
-aaa




# a A b B c Cを含む行にマッチ ※ロケール設定に依存
grep -i [a-c] gr.txt
# 結果
aaaa
bbbb
cccc
-aaa
AAAA




# 直前の1文字が、直前の文字も含めて2回繰り返されている
grep "a\{2\}" gr.txt
# 結果
aaaa
-aaa




# 直前の1文字が直前の文字も含めて2回以上、4回未満繰り返されている
grep "a\{2,4\}" gr.txt
# 結果
aaaa
-aaa



# "aaaa"の行を抽出
grep "^a\{4\}$" gr.txt
# 結果
aaaa




# 再利用　ホールドスペース　\(xxxx\) ちょっとかわいい
grep "\(a\)" gr.txt
# 結果
-aaa
aaaa




# "a"が2回登場する \1-9
grep "\(a\)\1" gr.txt
# 結果
-aaa
aaaa




# EREの正規表現
# BREの\{\}と同じ
grep -E "a{1,2}" gr.txt
# 結果
-aaa
aaaa




# 直前の正規表現が1回以上出現 aaaaはでない aaaaaはでる
grep -E "aaaa.+" gr.txt
# 結果
(出力なし)




# 直前の正規表現が0回または1回出現 aaaaは出る aaaaaはでない
grep -E "aaaa.?" gr.txt
# 結果
aaaa




# |でorがつかえる
grep -E "^aaa|^bbb" gr.txt
# 結果
aaaa
bbbb




# ()で囲まれた部分にマッチング bbbbかaaaa
grep -E "^(bbbb|aaaa)$" gr.txt
# 結果
aaaa
bbbb




```

# sed

```sh



# sed による置換　

# 区切り文字はなんでもよい
# 区切り文字は、置換対象になる場合、\でエスケープする必要があるので、"/"は避けるべし
  # /を区切り文字にした煩雑な例　./aaa/bbb/ccc.txt を　./ddd/eee/fff.txtに置換
  sed s'/.\/aaa\/bbb\/ccc.txt/.\/ddd\/eee\/fff.txt/g'

# ";"が多い気がする。私は"#"が好き
# 例：sed 's;yama;tetsu;'

# printfコマンドの"aaaa"を"bbbb"に置換
printf "%b" "aaaa\n" "bbbb\n" |sed 's#aaaa#bbbb#'

# 結果
bbbb
bbbb


# 後ろに"g"をつけると、全て置換
# 後ろに数字nをつけると、n番目を置換

   # 例 s/aaa/bbb/    1つめのaaaだけをbbbに置換
   # 例 s/aaa/bbb/1    1つめのaaaだけをbbbに置換
   # 例 s/aaa/bbb/2    2つめのaaaだけをbbbに置換
   # 例 s/aaa/bbb/g    すべてのaaaだけをbbbに置換


# n番目って何を基準に決めてるの？？

# 下記コマンドをパイプラインでsedに渡して検証
printf "%b" "a\n" "a\n" && printf "%b" "a\n"
# このコマンドの出力結果は以下
a
a
a

# 実験1 なし
(printf "%b" "a\n" "a\n" && printf "%b" "a\n")|sed 's#a#b#'
# 結果
b
b
b


# 実験2 1
(printf "%b" "a\n" "a\n" && printf "%b" "a\n")|sed 's#a#b#1'
# 結果
b
b
b


# 実験3 2
(printf "%b" "a\n" "a\n" && printf "%b" "a\n")|sed 's#a#b#2'
# 結果
a
a
a


# 実験4  1個目のaをaaにしてみる
(printf "%b" "aa\n" "a\n" && printf "%b" "a\n")|sed 's#a#b#'
# 結果
ba
b
b


# 実験5
(printf "%b" "aa\n" "a\n" && printf "%b" "a\n")|sed 's#a#b#1'
# 結果
ba
b
b


# 実験6
(printf "%b" "aa\n" "a\n" && printf "%b" "a\n")|sed 's#a#b#2'
# 結果
ab
a
a

# 実験7
(printf "%b" "aa\n" "a\n" && printf "%b" "a\n")|sed 's#a#b#g'
# 結果
bb
b
b


# 結論
# 行ごとにn番目という意味




# sed '場所(行) コマンド'

# printfで2行目に出力されるaaだけをbbに置換する方法
printf "%b" "aa\n" "aa\n" |sed '2 s#a#b#g'
# 結果
aa
bb



# printfで最終行に出力されるaaだけをbbに置換する方法 $
printf "%b" "aa\n" "aa\n" "aa\n"|sed '$ s#a#b#g'
# 結果
aa
aa
bb




# find に渡す
find ./ |sed 's#aaaa#bbbb#g'
# 結果
#./aaaa/aaaa.txt → ./bbbb/bbbb.txt




# 検索箇所から一番階層の近い場所にある1個目の"aaaa"を"bbbb"に置換
find ./ |sed 's#aaaa#bbbb#1'
# 結果
# ./aaaa/aaaa.txt → ./bbbb/aaaa.txt




# 利用ファイル準備
printf '%s\n' "aaaa" "bbbb" "AAAA" "BBBB" "-aaa" >sd.txt
cat sd.txt
# 結果
aaaa
bbbb
AAAA
BBBB
-aaa




# catで渡す
cat sd.txt |sed 's#aaaa#bbbb#1'
# 結果
bbbb
bbbb
AAAA
BBBB
-aaa




# -e で複数のコマンドを羅列できる
cat sd.txt |sed -e 's#aa#bb#1' -e '1 s#AA#BB#1'
# 結果
bbaa
bbbb
AAAA
BBBB
-bba




# 接頭が「-」は消し、冒頭 "^" を "mkdir " に置換
cat sd.txt |sed -e 's#^-##g' -e 's#^#mkdir #1'
# 結果
mkdir aaaa
mkdir bbbb
mkdir AAAA
mkdir BBBB
mkdir aaa




# 実行
cat sd.txt |sed -e 's#^-##g' -e 's#^#mkdir #1'|sh
# 結果
total 8
drwxr-xr-x  2 t-yamamoto  staff  68  1 27 16:43 1111
drwxr-xr-x  2 t-yamamoto  staff  68  1 27 16:43 2222
drwxr-xr-x  2 t-yamamoto  staff  68  1 27 16:43 AAAA
-rw-r--r--  1 t-yamamoto  staff  40  1 27 15:45 a.txt
drwxr-xr-x  2 t-yamamoto  staff  68  1 27 16:43 bba
drwxr-xr-x  2 t-yamamoto  staff  68  1 27 16:43 bbaa
drwxr-xr-x  2 t-yamamoto  staff  68  1 27 16:43 bbbb
drwxr-xr-x  2 t-yamamoto  staff  68  1 27 16:43 cccc
drwxr-xr-x  2 t-yamamoto  staff  68  1 27 16:43 dddd




# aaを含む列に対してのみ、aをbに置換
(printf "%b%b" "aaaa\n" "baab\n" && printf "%b%b" "abba\n" "aaaa\n" )|sed '/.*aa.*/ s#a#b#g'
# 結果
bbbb
bbbb
abba
bbbb




# sed '/文字列や正規表現/,/文字列や正規表現/ コマンド'
# aaを含む列から、baを含む列までの間で、aをbに置換
(printf "%b%b" "aaaa\n" "baab\n" && printf "%b%b" "abba\n" "aaaa\n" )|sed '/.*aa.*/,/.*ba.*/ s#a#b#g'
# 結果
bbbb
bbbb
abba
bbbb




# "aaaa"を含まない行を置換 !
cat sd.txt |sed '/aaaa/ !s#a.*#b#g'
# 結果
aaaa
bbbb
AAAA
BBBB
-b




# \で行を指定する区切り文字を変える
cat sd.txt |sed '\#aaaa# !s#a.*#b#g'
# 結果
aaaa
bbbb
AAAA
BBBB
-b




# sed -n は修正された行の出力をしない
# pコマンドで指定した行をそのまま出力する　1行目を出力
printf "%b%b" "aaaa\n" "baab\n" "aaa\n" |sed -n '1,2p'
# 結果
aaaa
baab



```

# cut

```sh

## printfで出力された"aa,bb"を、,で区切り2フィールド目を出力
printf "%b,%b" "aa" "bb" |cut -d , -f 2
# 結果
bb




# /etc/passwdからホームディレクトリのフィールドを抽出 -d -f
cut -d : -f 6 /etc/passwd




# 行頭の1〜3文字目を抽出 -c
printf "%b" "123456\n" "654321\n" | cut -c 1-3
123
654




```

# join

```sh

# 事前ファイル準備
printf "%b %b\n" "#Name" "BloodType" "Takashi" "A" "Itao" "B">jn.txt
printf "%b %b\n" "#Name" "Sex" "Takashi" "Man" "Itao" "Man">jn2.txt
cat jn.txt jn2.txt
# 結果
#Name BloodType
Takashi A
Itao B
#Name Sex
Takashi Man
Itao Man




# join でマージ
join jn.txt jn2.txt
# 結果
#Name BloodType Sex
Takashi A Man
Itao B Man




# 2つのファイルで行の順番が異なる場合、ソートする必要がある
# 事前ファイル準備
printf "%b %b\n" "#Name" "BloodType" "Itao" "B" "Takashi" "A">jn.txt
printf "%b %b\n" "#Name" "Sex" "Takashi" "Man" "Itao" "Man">jn2.txt
cat *jn*.txt
# 結果
#Name BloodType
Itao B
Takashi A
#Name Sex
Takashi Man
Itao Man




# sort
sort jn.txt>jn_sort.txt
sort jn2.txt>jn2_sort.txt
cat *sort*
# 結果
#Name Sex
Itao Man
Takashi Man
#Name BloodType
Itao B
Takashi A




# 並べ替えしたファイルをjoin
join *sort*
# 結果
#Name Sex BloodType
Itao Man B
Takashi Man A




# ヘッダを削除してjoin  sed'/xxx/d' sedのdeleteコマンドで#を消す
join *sort* |sed '/#/d'
# 結果
Itao Man B
Takashi Man A



# jn2.txtの1フィールド目をキーにしてjoin
  # join -1 file1のキー -2 file2のキー file1 file2
join -2 1 jn.txt jn2.txt
#Name BloodType Sex
Takashi A Man
Itao B Man




# 区切り文字が:のファイルをjoin
printf "%b:%b\n" "yama" "/bin/bash">logs.txt
printf "%b:%b\n" "yama" "yama_group">grp.txt
cat logs.txt grp.txt
# 結果
yama:/bin/bash
yama:yama_group

# join -t
join -t : grp* logs*
# 結果
yama:yama_group:/bin/bash




```

# awk

```sh

# 事前準備
printf "%b\n" "yama:/bin/bash" "Itou:/bin/ksh" >aw.txt
cat aw.txt
# 結果
yama:/bin/bash
Itou:/bin/ksh



#awk option '{コマンド}' Filename

# -F 入力のフィールド区切り文字を:にする例
# $1は1フィールド目を出力
awk -F : '{print $1}' aw.txt
# 結果
yama
Itou

# $0は全てのフィールド
awk -F : '{print $0}' aw.txt
# 結果
yama:/bin/bash
Itou:/bin/ksh




# -v 環境変数設定
# OFS 出力の区切り文字
awk -F : -v 'OFS=####' '{print $1,$2}' aw.txt
# 結果
yama####/bin/bash
Itou####/bin/ksh




# 文字列と一緒に出力
awk -F : -v 'OFS=\t' '{print "User:: "$1,"LoginShell:: "$2}' aw.txt
# 結果
User:: yama	LoginShell:: /bin/bash
User:: Itou	LoginShell:: /bin/ksh




# 文字列と一緒に出力2 printf
awk -F : '{printf "User:: %s\tLoginShell:: %s \n",$1,$2}' aw.txt
# 結果
User:: yama	LoginShell:: /bin/bash
User:: Itou	LoginShell:: /bin/ksh




# $NFで最終フィールドを取得
printf "%b\n" "a:b:c:d:e:f" "" "a:b:c:d:e:f" |awk -F : '{printf "LastField:: %s \n",$NF}'
# 結果
LastField:: f
LastField::
LastField:: f




# 空行以外を全て出力 $0は全てのレコード
printf "%b\n" "a:b:c:d:e:f" "" "a:b:c:d:e:f" |awk -F : 'NF > 0 {print $0}'
# 結果
a:b:c:d:e:f
a:b:c:d:e:f


# フィールド区切りとレコード区切り

# :をフィールド区切りにして1〜4フィールド出力
printf "%b\n" "a:b:c:d:e:f" "" "a:b:c:d:e:f" |awk -F : 'NF > 0 {print $1,$2,$3,$4}'
# 結果
a b c d
a b c d




# /をレコード区切りにして1〜4レコード出力
# レコードセパレータは任意の1文字(正しい情報じゃないかもしれない)
printf "%b" "a:b/c:d/e:f/g:h/" |awk -v 'RS=/' '{print$1,$2,$3,$4}'
# 結果
a:b
c:d
e:f
g:h



# フィールド区切りとレコード区切りを一緒に使う
printf "%b" "a:b/c:d/e:f/g:h" | awk -F : -v 'OFS=\t' -v 'RS=/' -v 'ORS=\n' '{print$1,$2}'
# 結果
a	b
c	d
e	f
g	h


# 空白区切りでならべる　改行をレコード区切りに指定して、半角スペースに置換
printf "%b\n" "a:b:c:d:e:f" "" "a:b:c:d:e:f" |awk -F : -v 'RS=\n' -v 'ORS= ' 'NF > 0 {print $0}' |tr ":" " "|sed 's# $##g'
#結果
a b c d e f a b c d e f t




# 1〜4フィールドだけ取り出してならべる　改行をレコード区切りに指定して、半角スペースに置換
printf "%b\n" "a:b:c:d:e:f" "" "a:b:c:d:e:f" |awk -F : -v 'RS=\n' -v 'ORS= ' 'NF > 0 {print $1,$2,$3,$4}'
# 結果
a b c d a b c d




# 上のaをbに置換　gsub関数
printf "%b\n" "a:b/c:d/e:f/g:h" | awk -F : -v 'OFS=\t' -v 'RS=/' -v 'ORS=\n' '{gsub("a","b");print$1,$2}'
b	b
c	d
e	f
g	h



# aをb bをc cをd dをe eをf fをg gをh に順番に置換
printf "%b\n" "a:b/c:d/e:f/g:h" | awk -F : -v 'OFS=\t' -v 'RS=/' -v 'ORS=\n' '{gsub("a","b");gsub("b","c"); gsub("c","d");gsub("d","e");gsub("e","f");gsub("f","g");gsub("g","h");print$1,$2}'
# 結果
h	h
h	h
h	h
h	h


```

# sort

```sh

# sort -t: -k1.1,1.2
# -t 区切り文字を指定
# -k キーとなる文字の開始フィールド.開始文字の位置,終了フィールド.終了文字の位置
printf "%b\n" "ab:ba" "ba:ab" |sort -t: -k1.2,1.2
# 結果
ba:ab
ab:ba

# r
sort ./passwd.txt -k2r -t:
# kekka
_krbfast:*:246:-2:Kerberos FAST Account:/var/empty:/usr/bin/false
daemon:*:1:1:System Services:/var/root:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false


# f は大文字と小文字を区別しない
# d 辞書順
sort ./passwd.txt -k2d -t:
# kekka
root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
_krbfast:*:246:-2:Kerberos FAST Account:/var/empty:/usr/bin/false


# uniq で重複排除
printf "%b\n" "aa:ba" "aa:ab" "aa:cc" "aa:dd" "aa:cc" |sort -t: -k2 |uniq
#結果
aa:ab
aa:ba
aa:cc
aa:dd


# 重複してない行だけ表示
printf "%b\n" "aa:ba" "aa:ab" "aa:cc" "aa:dd" "aa:cc" |sort -t: -k2 |uniq -u
# 結果
aa:ab
aa:ba
aa:dd



# 重複行のみ
printf "%b\n" "aa:ba" "aa:ab" "aa:cc" "aa:dd" "aa:cc" |sort -t: -k2 |uniq -d
# 結果
aa:cc



# 登場回数も表示
printf "%b\n" "aa:ba" "aa:ab" "aa:cc" "aa:dd" "aa:cc" |sort -t: -k2 |uniq -c
# kekka
   1 aa:ab
   1 aa:ba
   2 aa:cc
   1 aa:dd

#もう一回sort
printf "%b\n" "aa:ba" "aa:ab" "aa:cc" "aa:dd" "aa:cc" |sort -t: -k2 |uniq -c |sort
  1 aa:ab
  1 aa:ba
  1 aa:dd
  2 aa:cc

# 登場回数順に表示
printf "%b\n" "aa:ba" "aa:ab" "aa:cc" "aa:dd" "aa:cc" |sort -t: -k2 |uniq -c|sort -r |awk '{print $2}'
# 結果
aa:cc
aa:dd
aa:ba
aa:ab



```

# 行指定の方法

```sh

# 今北産業の(ファイルの末尾3行)表示
tail -f -n 3 passw*
# kekka
root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
_krbfast:*:246:-2:Kerberos FAST Account:/var/empty:/usr/bin/false


# awkのFNR で行番号を指定
printf "%b\n" "a" "b" "c" |awk 'FNR <= 1'
# 結果
a


# sedのqコマンドで指定した行まで表示
printf "%b\n" "a" "b" "c" |sed 2q
# 結果
a
b


# headコマンド
printf "%b\n" "a" "b" "c" |head -2
# 結果
a
b



```

# ここからは自由に

```sh


# cdコマンドを作りかえる
cd () { command cd "$@"; x=$(pwd); PS1="${x##*/}\$"; }



# while文 ユーザー名とログインシェルをタブ区切りで取り出す
# また、変数aの文字列aをwhileループ内でbに変更
a="a"

while IFS=: read user pass uid gid fullname homedir logshell
do
  printf "%b" "${user}\t" "${logshell}\n"
  a="b"
done </etc/passwd

echo $a # aはbになる



# 上と同じことを別の方法で　catしてパイプで渡してみる
# 変数aの文字列aをwhileループ内でbに変更
a="a"

cat /etc/passwd |
while IFS=: read user pass uid gid fullname homedir logshell
do
  printf "%b\t" "${user}\t" "${logshell}\n"
  a="b"
done

echo $a # aはaのまま つまり、パイプで渡すと外部変数は変更されない・・



# 上と同じこと2
# RSとORSはデフォルトと同じなので別にいらないが、あえて意識した
cat /etc/passwd |awk -F : -v 'RS=\n' -v 'ORS=\n' -v 'OFS=\t' '{print $1,$7}'


# 上と同じこと3
# プロセス置換 <(list)
awk -F : -v 'RS=\n' -v 'ORS=\n' -v 'OFS=\t' '{printf "%s\t%s\n",$1,$NF}' <(cat /etc/passwd)


# 上と同じこと4
a="a"

while IFS=: read user pass uid gid fullname homedir logshell
do
  printf "%b" "${user}\t" "${logshell}\n"
  a="b"
done< <(cat /etc/passwd)

echo $a #もちろんaはbに　

#コマンドの結果をreadに渡して、ループ内で外部変数の書き換えを行う際には、
#bashの機能であるプロセス置換を用いることにより、一時ファイルを作らなくて良くなる




# 変数の展開
a="abcd/efgh/ijkl/mnop"

# 先頭から1文字目だけ表示
printf "%b\n" ${a::1}
a

# 先頭から2文字目まで表示
printf "%b\n" ${a::2}
ab


# 先頭から1文字目だけ表示 上とおなじこと
printf "%b\n" ${a:0:1}
a


# 2文字目から2文字表示
printf "%b\n" ${a:1:2}
bc



# abcが定義されていない場合にnodefと返す
printf "%b\n" ${abc-nodef}
nodef




# abcが定義されていない場合にnodefと返しスクリプトを強制終了
printf "%b\n" ${abc?nodef}
-bash: abc: nodef