メインコンテンツへ移動

ファイル_bashノート3

無料2017-03-19#Tool#linux文件权限#diff命令#vps硬盘测速#linux文件名空格

ファイルに関する常識とよく使われるコマンド

UNIXシステムはすべてをファイルとして扱います。コマンドターミナルでさえデバイスファイルと関連付けられており、そのファイルに書き込むことでターミナルに情報を表示させることができます。例えば:

# 現在のターミナルに出力する
echo hoho > /dev/tty

# bash環境で、ttys001ポートに接続されているターミナルに送信する
echo hoho > /dev/ttys001

dd

指定したサイズのファイルを生成するために使用され、ハードディスクの読み書き速度の測定によく使われます。

// テストファイル test.data を生成する
// \0 で埋め尽くし、サイズは 10M とする
dd if=/dev/zero of=test.data bs=1024 count=10k

// 書き込み速度の測定
// ディスクに連続書き込みを行い、メモリバッファを使用せず、毎回 8k のデータを書き込み、計 4k 回実行して 32M のファイルを生成する
dd bs=8k count=4k if=/dev/zero of=test.data conv=fdatasync

// 読み込み速度の測定
dd if=test.data of=/dev/null bs=4k

if は入力ファイル(input file)、of は出力ファイル、bs は書き込みブロックのサイズを表します。/dev/zero は無限の \0 文字を生成する特殊なデバイス、/dev/null は入力をすべて捨てる空のデバイスです。

P.S. Mac の dd では conv 引数に fdatasyncfsync オプションはありません。

comm

comm コマンドはテキストファイルを比較して差分を表示します。ただし、入力ファイルはソートされている必要があるため、通常は sort と組み合わせて使用します:

# sortコマンドの -o オプションはファイルへの出力を指定。ここでは元のファイルを直接上書きする
sort a.txt -o a.txt; sort b.txt -o b.txt
# diffを実行
comm a.txt b.txt

P.S. wget-O- オプションは面白い形をしており、ファイルとして取得して結果を STDOUT に出力することを意味します。

結果は以下の3列で得られます:

# aにありbにないもの  bにありaにないもの  両方にあるもの
    a - b               b - a             a ∩ b

この3列があれば、元のファイル a と b を復元できます(ソート済みのもので、ソート前には戻せません)。例えば a = (a - b) ∪ (a ∩ b) です。

-1/-2/-3 オプションで指定した列を削除できます。オプションは入力ファイルの前に記述する必要があります:

# 第3列を削除し、共通部分(a ∩ b)を出力しない
comm -3 a.txt b.txt

# abの差異を1列にまとめ、差異のある行のみを出力する
comm -3 a.txt b.txt | sed $'s/\t//g'

特に注意:正規表現の前の $ は値の展開を意味します。これを付けないとタブ文字にマッチしません。IFS=$'\n' と同じ理屈です。

P.S. Mac の sed -i によるインプレース置換は非常に面倒で、バックアップファイル名を指定する必要があります(空文字列でも可)。

diff

差異ファイルを生成するために使用されます:

# -u オプションで一般的なフォーマットを出力し、diff.txt に書き込む
diff -u a.txt b.txt > ab.diff

行単位でファイルを比較し、どの行が追加・削除されたかを示します(変更は削除と追加の組み合わせとして扱われます)。結果は以下のようになります:

--- a.txt    2017-03-15 10:50:34.000000000 +0800
+++ b.txt   2017-03-19 16:56:14.000000000 +0800
@@ -1,6 +1,11 @@
+
+end yaya
 data
-end
 is
-line
 no
+line
 this
+
+newend
+line

diff の結果を使用してパッチを当てることで、ファイルを復元・変換できます:

# aにパッチを当てる
patch -p1 a.txt < ab.diff
# abの内容が同じになる
md5 a.txt; md5 b.txt

元の内容に戻すには、もう一度 patch を実行します:

# パッチを戻す
patch -p1 a.txt < ab.diff

ディレクトリに対しても diff を行えます:

# -N は存在しないファイルを空ファイルとして扱う、-a はすべてのファイルをテキストとして扱う、-r はディレクトリを再帰的に比較する
diff -Naur data files

mkdir

ディレクトリを作成するために使用されます。既に存在する場合はエラーを返します:

mkdir: bak: File exists

通常はチェックが必要です:

# 存在しない場合のみ作成する
if [ ! -e path ]; then mkdir $path; fi

深いパスの場合、各階層をチェックするのは面倒なので、エラーを捨てることもできます:

mkdir ./dir1 2>/dev/null
mkdir ./dir1/dir2 2>/dev/null
mkdir ./dir1/dir2/dir3 2>/dev/null

より簡単な方法は:

mkdir -p ./dir1/dir2/dir3

既に存在する場合は無視し、必要なディレクトリのみを作成します。

ファイル権限

一般的な3つのカテゴリ:

  • user:ファイルの所有者

  • group:ユーザーグループ

  • others:所有者とグループ以外のユーザー

ls -l で表示される権限の形式は:ファイルタイプ(1文字) 所有者権限(3文字) グループ権限(3文字) その他権限(3文字) です。

ファイルタイプは以下の通りです:

- 通常ファイル
d ディレクトリ
c キャラクタデバイス
b ブロックデバイス
l シンボリックリンク
s ソケット
p パイプ

後ろの権限は、各カテゴリにつき4つの値(-rwx)があり、それぞれ なし/読み取り/書き込み/実行 を表します。

P.S. 権限が ---------- の場合、root 以外のすべてのユーザーはそのファイルに対して一切の操作(読み書き実行)ができません。

また、x の位置に表示される3つの特殊権限があります:

  • setuid:ユーザーが所有者の権限でファイルを実行できる。例:-rws------

  • setgid:ユーザーが所有グループの権限でファイルを実行できる。例:----rws---

  • sticky bit:スティッキービット。そのディレクトリを作成したユーザーのみが配下のファイルを削除できる。他のユーザーは書き込み権限があっても削除できない。例:-------rwt

注意:st には大文字と小文字があり、小文字は x 権限があることを、大文字は x 権限がないことを表します。

権限の変更

chmod コマンドを使用します。例えば:

# 権限を設定する
chmod u=rwx g=rwx o=rwx test.sh
# 所有者に実行権���を追加する
chmod u+x test.sh
# 全員に実行権限を追加する
chmod a+x test.sh
# 所有者の実行権限を削除する
chmod u-x test.sh

数値を使って設定することもできます:

# u=rwx g=rwx o=rwx と同等
chmod 777 test.sh

777rwx の2進数表現を10進数にした3つの組です。例えば r-- は 4(100)です。

P.S. 一般にこれは8進数と呼ばれますが(0から7の値)、実際には2進数として解釈する方が合理的です。

3つの特殊権限の設定も chmod で行います:

# setuid, setgid, sticky bit
chmod u+s
chmod g+s
chmod o+t

数値で設定する場合、3つの権限の前に sst の組を追加します。例えば chmod 2777 test.sh の特殊権限は 2(010)で、これは setgid 権限を意味します。

所有権を変更するコマンドは chown です:

# 所有者を user1 に、グループを staff に設定する
chown user1.staff test.sh

通常、setuid 権限と組み合わせて使用されます:

# rootグループのrootユーザーにする
chown root.root bomb.sh
# 所有者実行権限を付与し、実行時にroot権限になるようにする
chown u+s bomb.sh

touch

touch コマンドは、ファイルが存在すればタイムスタンプを更新し、存在しなければ空のファイルを作成します:

# 存在すれば、すべてのタイムスタンプを現在時刻に更新する
touch test.sh
# 存在すれば、アクセス時刻のみ更新する
touch -a test.sh
# 存在すれば、修正時刻のみ更新する
touch -m test.sh

head/tail

ファイル内容の一部のみを表示します:

# 最初の10行を表示
head test.sh
# 最初の3行を表示
head -n 3 test.sh
# 最後の10行を除外して表示
head -n -10 test.sh

# 最後の10行を表示
tail test.sh
# 最後の3行を表示
tail -n 3 test.sh
# 最初の90行を除外して表示(91行目から最後まで出力)
seq 100 | tail -n +91

P.S. Mac では -n 引数に負の数を指定できず、head: illegal line count -- -10 というエラーになります。

ls でディレクトリのみを列挙する

3つの方法があります:

# -d オプションが最も簡潔
ls -d */
# -F でタイプ識別子を付け、/ で終わるものを抽出
ls -F | grep "/$"
# -l の結果(権限の先頭文字がタイプ)から d で始まるものを抽出
ls -l | grep "^d" | awk '{print $9"/"}'

find を使うこともできます:

# ファイルタイプを指定して検索
find . -type d -maxdepth 1 -mindepth 1 -print

1階層下のみを探すよう、depth の範囲に注意してください。

パスの切り替え

cd - (cd $OLDPWD) で直前のディレクトリに戻ることはよくありますが、さらに強力なものがあります:

# cd と同じように動作するように見える
pushd /tmp
# 履歴スタックを確認 (-v で番号表示)
dirs -v
# 直前のディレクトリに戻る
pushd
# その前のディレクトリに戻る
pushd +1
# さらにその前の...
pushd +2

pushd は作業ディレクトリを切り替え、スタックの先頭と指定した記録を入れ替えますが、スタックの長さは変わりません。記録を削除して戻る場合は popd を使います:

# 直前のディレクトリに戻り、現在のパスを削除する
popd
# 指定した履歴パスを削除する
popd +1
# 履歴スタックをクリアする(現在のパスのみ残す)
dirs -c

+N-N は方向を表し、+N はスタックの先頭から 0123... と数え、-N はスタックの底から数えます。

P.S. oh my zsh の特定のバージョンでは +- の方向が逆になっていることがありますが、bash は正常です。

wc

行数、単語数、文字数をカウントします。簡単なコード統計によく使われます:

# 行数、単語数、文字数を出力
wc test.sh
# 行数のみ取得
wc -l test.sh | awk '{print $1}'
# 単語数のみ取得
wc -w test.sh | awk '{print $1}'
# 文字数のみ取得
wc -c test.sh | awk '{print $1}'

P.S. 単語カウント機能は弱く、スペースで区切られた文字列を1つの単語として扱い、句読点の区別もされません。

コメント

コメントはまだありません

コメントを書く