シェルの書き方、正規表現、文法を学習のために1つ1つ記述していきます。
- 2月中めどで、だいたい網羅します。
- 何かのお役に立てますと幸いです
- シェルマスターに俺はなる
はじめに
# ! /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
# 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
# 事前準備
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
# 事前準備
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
# 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
## 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
# 事前ファイル準備
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
# 事前準備
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
# 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
行指定の方法
# 今北産業の(ファイルの末尾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
ここからは自由に
# 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