Linuxの基本(その3)テキスト関連

目次
  1. 文字列の扱いについて
  2. テキストストリームの処理
    1. head・tail・cut
    2. expand・unexpand
    3. pr・fmt・sort
    4. uniq・tr
    5. split・join・paste
    6. od・nl・wc
  3. ワイルドカードと正規表現について
    1. ワイルドカード
    2. 正規表現
  4. sedコマンドとgrepコマンド
    1. sedコマンド
    2. grepコマンド
  5. teeコマンドとxargsコマンド

文字列の扱いについて

文字と文字列

・文字:記号としての文字
・文字列:文字の集まり

コマンドラインで使用する「引用符(文字列を囲む)」の種類と解説
種類解説
' 'すべて文字列とみなされる
" "変数は展開される
` `コマンド結果が展開される

テキストストリームの処理

コマンドからのテキストデータの流れを「ストリーム」といいます
コマンドへ入る「ストリーム」は「標準入力」、コマンドから出る「ストリーム」は「標準出力(正常)」と「標準エラー出力(エラーメッセージ)」です

フィルタをとおして出力を変更するコマンドでは、「抽出結果」を別ファイルとして保存するには、リダイレクトを使用します

「lessコマンド・catコマンド」以外の、「テキストストリームを処理するコマンド」をざっくりとまとめました

head・tail・cut

行または列を切り取る
head [ オプション ] [ ファイル名 ]
ファイルの先頭から表示する
–行数: 先頭から行数分表示
–c バイト数: バイト数だけ先頭から表示
tail [ オプション ] [ ファイル名 ]
ファイルの末尾から表示
–行数: 末尾から行数分表示
–c バイト数: バイト数だけ末尾から表示
–F: ファイルの末尾に追加されるテキストをリアルタイムに表示
cut [ オプション ] [ ファイル名 ] 
列を編集して表示(各行から一部分を切り出す)
-d 文字 -f フィールド番号
 -d 文字 : 区切り文字を指定(デフォルトの区切り文字はタブ)
 -f フィールド番号:切り出すフィールド番号を指定
 (フィールドは、区切り文字で区切られ一番左のフィールドを「1」
  また、「-」で範囲指定や「,」で複数のフィールドを指定できます)

-c [n] [m]: 切り出す文字位置を指定(文字位置は一番左の文字を「1」)
数字で指定する(nとmは数)
 n: nを切り出します
 n-:nから行末までを切り出す
 n-m:nからmまでを切り出す
 -m :行頭からmまでを切り出す

expand・unexpand

「タブとスペース」の変換
expand [ オプション ] [ ファイル名 ]
テキスト内のタブをスペースに変換
-t 文字数: タブの文字数を指定(デフォルトは8)
-i: 行頭のタブのみを変換
unexpand [ オプション ] [ ファイル名 ]
行頭のスペースをタブに変換
-t 文字数 --first-only: タブの文字数を指定(デフォルトは8)
-a: 行頭以外のスペースも変換

*ちなみにタブは「見えない文字」で、開始位置を揃える目的で使われます
スペースは「1文字分の空白」です

pr・fmt・sort

ファイルを整形するコマンド
pr [ オプション ] [ ファイル名 ]
印刷用の整形
開始 [: 終了]: 開始ページや終了ページを指定する
-h ヘッダ文字列: ヘッダに表示されるファイル名を指定した文字列に変換する
-l 行数: ヘッダとフッタを含めたページの長さを行数で指定する
fmt [ オプション ] [ ファイル名 ]
幅を整形(単語は分割されません)
デフォルトは75桁
各行の幅と比較より、オプションで指定した幅が広い場合は、行が結合されます
-w 文字数: 1行の幅を指定
-s: 結合はしない
-u: 単語間のスペースを1スペースに整形
sort [ オプション ] [ ファイル名 ]
ファイルの行を並べ替える
*デフォルトでは左側にある文字から昇順にソートされる(数字も文字として解釈される)
–n: 数字でソートする(数字で降順は-nr)
–r: 降順にソートする
–b: 行頭のスペースを無視 (行頭にスペースがあるとその行がソートの先頭にくる)
–f: 大文字小文字を区別しない

–t 区切り文字: 指定した文字を区切り文字とする
–k n: n番目(フィールドの一番左「1」)をソート対象とする

–R: ランダムにソートする

uniq・tr

テキストの削除や置換をするコマンド
uniq [ オプション ] [ 入力ファイル名][ 出力ファイル名 ]
ファイルから重複している行の表示または削除
事前にソートが必要(重複行が隣り合っている必要がある)
引数に出力ファイル名を指定することができます(リダイレクトをつかわずにファイル保存できる)
–i: 大文字小文字を区別しない
-d: 重複している行のみを取り出す
-u: 重複していない行を取り出す
tr [ オプション ]
文字の変換や消去
ファイル名を引数にとらないので「ファイルの内容を処理したい場合」は「ファイル名 |」か「< ファイル名」
–d 文字セット: 文字セットでマッチした文字を削除 (文字セットがややこしい(^_^;) 例えば、文字セットが’ab’の場合「aとb」が対象になる「ab」ではない)
–s 文字セット: マッチした文字が連続する場合1文字にする(文字セットが’a’の場合「aaa」は「a」に、「aaabaaa」は「aba」になる)

[ 文字セット1] [ 文字セット2]:[ 文字セット1]を[ 文字セット2]に変換 
例えばtr 'a-z' 'A-Z'で英文字をすべて大文字に変換する
文字セットに、[特定の文字集合]を使うことができ、’a-z’は[:lower:]・’A-Z’は[:upper:]
 [:alpha:] 英字
 [:lower:] 英小文字
 [:upper:] 英大文字
 [:digit:] 数字
 [:alnum:] 英数字
 [:space:] スペース

split・join・paste

1つのファイルを分割する・2つのファイルを結合する
split [ オプション ] [ 入力ファイル名 ] [ プレフィックス ]
1つのファイルを分割して、複数のファイルを作ります
デフォルトは1000行ごとに分割
プレフィックスのデフォルト値は「x」で、ファイル名は「xaa・xab・xac ..」になります
-行数: 何行ごとに分割するかを指定する
-b バイト数: バイト数で分割
join [ オプション ] [ ファイル名1 ] [ ファイル名2]
2つのファイルの行を共通フィールドで結合する
splのような使い方
フィールド番号は、1行中のスペースまたはタブで分割したときの個々の要素で、一番左のフィールド番号が「1」です
オプションを省略すると、一番左のフィールドが結合キーとして使用される
-j フィールド番号: 結合キーとなるフィールド番号を指定する
-1 フィールド番号: ファイル名1の結合キーとなるフィールド番号を指定する
-2 フィールド番号: ファイル名2の結合キーとなるフィールド番号を指定する
paste [ オプション ][ ファイル名1 ] [ ファイル名2] …
2つのファイルの行を行番号で結合する(行番号が同じ行を水平に連結)
-d "区切り文字": 連結部の区切り文字となる1文字を指定します(デフォルトはタブです)

od・nl・wc

od [ オプション ] [ ファイル名 ]
ファイルの形式を8進数などで表示
-to: 8進数で表示
-tx: 16進数で表示
-tc: ASCII文字で表示
nl [ オプション ] [ ファイル名 ]
ファイルの行頭に行番号をつけて表示
*ヘッダ、本文、フッタをつけるのが本来の使い方のようです^^;
-bt: 全ての行 (cat -nと同じ)
-ba: 空白以外の行 (cat -bと同じ)
wc [ オプション ] [ ファイル名 ]
ファイルの行数・単語数・文字数を表示
ファイル名を省略すると標準入力から受け取ります
-l: 行数を表示
-w: 単語数を表示
-c: 文字数を表示

ワイルドカードと正規表現について

「正規表現」のほうが「ワイルドカード」よりも複雑で、できることも多いです
「正規表現」では「場所を指定したり」「文字を複数指定したり」ができます

ワイルドカードで「*」は、任意の長さの文字で、文字を表していますが、正規表現で「*」は、「直前の文字の0回以上の繰り返し」で文字ではありません

ワイルドカード

ワイルドカードは(複数の文字に合致する特殊文字です)
findコマンドの条件としても使えます
*
任意の長さの文字
a* は、「a ab abc abcd 」など
?
任意の1文字
a? は、「ab ac ad」 など
[ ]
カッコ内の任意の文字(ハイフンで範囲を指定)
[0-9] 任意の数字1文字
[a-z] 任意のアルファベット1文字(小文字)
[A-Z] 任意のアルファベット1文字(大文字)
[a-zA-Z]任意のアルファベット1文字
[! ]
カッコ内以外の任意の文字
{ }
カッコ内の任意の文字列(複数は「,」で区切る)
{abc, def} は、「abcかdef」
ワイルドカードと正規表現の比較
ワイルドカード正規表現
*.*任意の長さの文字
?.任意の1文字
?直前の文字が全くないか、1回だけある
[ ][ ]カッコ内の任意の文字
[! ][^ ]カッコ内以外の任意の文字
{ , }{|}カッコ内の任意の文字列

正規表現

正規表現とは、文字列のパターンを表現する表記法です
いくつかの記号(メタ文字)でパターンを表現します
メタ文字の例  . * [] {} () + ¥ ^ $ など

\ (エスケープ)は、メタ文字を「普通の文字」として表現するときに、「文字である」ことがわかるようにメタ文字の前につけます

マッチする文字を指定する
1
1だけマッチする
ab
abだけマッチする
.
任意の1文字
hoge.は、hoge1でもhogeAでもマッチする
hogeはマッチしない
[ ]
カッコ内の任意の文字
[ab]_123であれば「a_123」でも「b_123」でもマッチする
[^ ]
カッコ内以外の任意の文字
[^0]  0以外
[^a]  a以外
[0-9]
任意の数字1文字
[a-z]
任意のアルファベット1文字(小文字)
マッチする位置を指定
^
行の先頭
^a
abcはマッチする
cbaはマッチしない
$
行の末尾
a$
cbaはマッチする
abcはマッチしない
繰り返しの回数
*
直前の項目の「0回以上」の繰り返し
?
直前の項目が「0回か、1回だけ」ある
+
直前の項目の「1回以上」の繰り返し
{n}
直前の項目が「n回」繰り返す
{n, }
直前の項目が「n回以上」で繰り返す
{ , m}
直前の項目が「m回以下」で繰り返す
{n,m }
直前の項目が「n回以上 、m回以下」で繰り返す

複数のパターンのどちらかにマッチさせる場合は
() でグループを作り、| で複数のアイテムのいずれ、()|()にする

指定した正規表現と一致する箇所を確認できるツール・シンプルで使いやすいです

sedコマンドとgrepコマンド

「sedコマンド」と「grepコマンド」の検索条件には、正規表現を使用できます

*拡張正規表現は、「egrep」 「grepコマンドの-Eオプション」「sedコマンドの-rオプション」で使用できます

「sedやgrepなどのLinuxコマンド」で基本正規表現を使うと「+で文字」「\+でメタ文字」とエスケープが逆になることがあります(POSIXで標準化されている基本正規表現と拡張正規表現の違いによるそうです)

ややこしいので、正規表現をつかうときは、拡張正規表現をつかおうと思います^^;

sedコマンド

sedコマンドは、「文字列を全置換したり」「文字列を削除したり」「行単位で抽出したり」さまざまなことができる「ストリームエディタ」です

基本の使いかた

sed [オプション] [[アドレス]コマンド] [ファイル名]

  • 「sedコマンド」は、処理結果をデフォルトで「画面に出力」します
  • 「-i」オプションを指定しない限り、ファイルは変更されません
  • 「ファイル名」を省略すると「標準入力」から受け取ります
  • 「アドレス」と「コマンド」の組み合わせで処理します
    「アドレス」は「行番号」や「正規表現」による指定ができます
    *正規表現にマッチする行だけを対象とすることができる
  • 「アドレス」を省略すると「全ての行」が対象となります
主なコマンド
s/置換前の文字列/置換したい文字列/
指定したパターンで変換
1行に複数マッチした場合は、各行の最初のマッチだけ置換する

1行に複数マッチした場合は、すべて置換する場合
s/置換前の文字列/置換したい文字列/g
置換前の文字列に正規表現がつかえます
y/元の文字列/対象文字列/
「tr」コマンドと同じようなつかい方(「ab」の場合「aとb」が対象)
1行に複数マッチした場合は、すべて置換する
p
処理した内容を出力します
通常はPがなくて出力されますが、「-n」オプションを付けると出力されません
「-n」オプション指定時(必要な行だけ取り出す)は「p」をつけます
d
指定した行を削除
sed 1,5d:1行目から5行目を削除
=
行番号を出力
i テキスト
テキストの挿入
テキストは、指定した位置の後ろにを挿入される
a テキスト
テキストの追加
テキストは、指定した位置の後ろにを挿入される
c テキスト
選択した行を、テキストで置換する
q
終了
未出力分があれば出力してから終了
Q
出力せずに終了する
よくつかうオプション
-n
pとセットで必要な行だけ取り出す
-n 1p : 1行だけ取り出す
-n 1,3p : 1行目から3行目まで取り出す
-i
出力せずにファイルを上書きで書き換える
-r コマンド
コマンドに拡張正規表現を使う
-e コマンド -eコマンド
複数のコマンドを指定する
-f ファイル名
指定したファイルからコマンドを受け取る

grepコマンド

「grepコマンド」は、ファイルの中身を検索して、指定した文字列(正規表現可)のある行を探します

grep [オプション] [検索したい文字列(正規表現可)] [ファイル名]
ファイルの中身を検索して、指定した文字列(正規表現可)のある行を探します
–i: 大文字小文字を区別しない
–v: [検索したい文字列]を含まない行を抽出
–E: 拡張正規表現を用いて文字を抽出(デフォルトでも正規表現は利用されます)
–F: 正規表現を利用しない
–n: 行数を一緒に抽出
-c: マッチした行数を表示

teeコマンドとxargsコマンド

tee [ オプション ] [ ファイル名 ]
標準出力で「画面表示」と「ファイルへの書き込み」の両方行います (「|」と利用されるケースが多い)
例えばcat /etc/passwd | tee hoge.txt で画面に表示され「hoge.txt」に保存される
–a: ファイルに追記する(デフォルトは上書き)
-i: 割り込みのシグナルを無視(Ctrl+「c」を無視)
xargs [オプション] [コマンド[引数]]
前のコマンドの実行結果を、次のコマンドの「引数」として渡す
*「コマンドの引数」として渡すとは、コマンドライン(入力行)を作成すると同じこと^^;
入力関係のオプション
-a ファイル名: ファイルから読み込む
-I 置換文字列: コマンドの引数のうち、置換文字部分を標準入力から読み込んだもので置き換える
-p: 1行ごとに実行確認をする
xargsコマンドがややこしい〜!!
「引数でわたす」と「標準入力でわたす」の違いについて
コマンドを実行するには、引数が必要な場合がある
例えば、rmでファイルを削除する時はファイル名を引数で指定する
だから、リストを標準入力で渡しても実行できない
#list.txt(削除したいファイル名の一覧リストを書いたファイル)があるとする

#標準入力で渡しても削除したいファイルは削除(rm)されない
cat list.txt | rm 

#xargsを使い引数でわたせば削除される(リストのファイル名とディレクトリが同じなら)
cat list.txt | xargs rm

# リストのファイル名とディレクトリが違う場合は、
# -Iオプションで適当な置換文字列(hoge)で置き換えて
# rmコマンドの引数にわたす
cat list.txt | xargs -Ihoge rm dir/hoge

# 引数の挿入位置を自分で指定する (-I {})
# リスト:hoge1.txt のように表示される
$ ls | xargs -I {} echo 'リスト: {}'

# 365日以内に作られた~/ディレクトリの一覧
find ~/ -type d -mtime +365 | xargs ls