自分用のLinuxコマンド・シェルコマンド備忘録
細かいけどメモしておきたいものが出てきたので、gitとvimに続いてLinuxコマンド・シェルコマンドの備忘録です。追記したいものが出てきたら随時編集します。
ファイル名がハイフンで始まるファイルを消したり、リネームしたりする
$ rm ./-foo.txt
この様に./
から書き始めます。
$ rm -foo.txt
こう書くとオプション扱いになってダメです。
ひとつ前のパスに移動する
$ cd ~ $ cd ../ $ cd -
この場合、cd -
で自分のホームディレクトリに移動できます。仕組みはよくわかりませんが、ハイフンで一つ前のディレクトリに移動出来るようです。ハイフンは$OLDPWDと同じだそう。id:calpoさんありがとうございます。
$ ls --
ls
の場合はls --
とハイフン2つで、ひとつ前のディレクトリ内を見れました。
実行中のコマンドをバックグラウンドに移行する
Ctrl+z ^Z [1]+ Stopped sudo port selfupdate $ bg 1 [1]+ sudo port selfupdate & $ jobs [1]+ Running sudo port selfupdate &
この例ではMacPorts*1のselfupdate
が、久しぶりの実行で割と長かったのでバックグラウンドに持っていってみました。
bg 1
の1
は省略すると、直近で止めたジョブを操作することになります。
$ fg 1 sudo port selfupdate
バックグラウンドからフォアグラウンドに持ってくる。処理中は標準出力にあまり何も出さないコマンドを実行中だと、フォアグラウンドに移行してからしばらく何も出ないのでちょっと心配になる。
ちなみに、selfupdate
は何かを解凍するのが長いらしくbzip2
がCPUを使ってました。Ctrl+z
で止めるとCPU使用率が下がり、bg
fg
で再開させると、またCPUリソースを食い始めるので、Ctrl+z
はほんとに止めてるみたい。
バックグラウンドのジョブをkillする
$ jobs [1]+ Running sudo port selfupdate & $ kill -15 %1
ジョブ番号は%
を付けて指定できます。
$ %1 $ fg 1
ついでに%1
でfg 1
と同様に、バックグラウンドからフォアグラウンドに移行出来ます。
終了ステータス*2
コマンド終了時には「終了ステータス(exit-status)」と呼ばれる、コマンドの成否を表す数値が特殊変数 $? に自動で設定される。 各コマンドにより異なるが、一般的にはコマンド成功時には「0」が、失敗時には「1」が設定される。
command echo $?→ 直前に実行したコマンドの成否は、特殊変数 $? に設定されている値で確認する。
終了ステータス | UNIX & Linux コマンド・シェルスクリプト リファレンス
ハイフンは標準出力、を表すことが多い
特に決まりというわけではないそうですが、多くのコマンドが、ハイフン(-)ひとつを標準入出力のことと読み替えて処理をしてくれます。
【linux】コマンドの結果を標準出力に出す at softelメモ
UNIX文化の習慣でハイフンは標準出力を表すことが多いらしい。でもあくまでコマンドそれぞれの実装しだいなんだとか。
ではwgetで試してみる。
wget -O index.html http://www.softel.co.jp/
wgetの結果はindex.htmlに保存される。では標準出力に出力して、パイプでwcに渡して行数を数えるには、
wget -O - http://www.softel.co.jp/ | wc
【linux】コマンドの結果を標準出力に出す at softelメモ
- Oオプションの保存先にハイフンを指定。
lnコマンドでシンボリックリンクを作る際のパス
ln
コマンドの引数に相対パスを使うとややこしい。ln -s シンボリックリンクを基準にした実ファイルへのパス 作るシンボリックリンクのパス
という事になり、一応書いてみたけど多分余計混乱する。
$ cd ~ $ ls usr/local/bin/ foo $ ls usr bar
この様に、~/usr/local/bin/foo
と~/bar
というファイルがあるとして、それぞれにシンボリックリンクを作る場合の例。
$ ln -s usr/local/bin/foo foo
実ファイル | ~/usr/local/bin/foo |
シンボリックリンク | ~/foo |
$ ln -s ../../../bar usr/local/bin/bar
実ファイル | ~/bar |
シンボリックリンク | ~/usr/local/bin/bar |
curlでHTTP Headerを確認する
$ curl -I GET http://example.com/
HTTP Headerが標準出力される。ただし、HTTP HEADメソッド。
$ curl -I -X GET http://example.com/
HTTP GETメソッドを指定する事もできる。
httpサーバーは、HEADに対しGETと同じHTTP Headerを返さないといけないルールになっているけど、何か事情があってGETとHEADで帰ってくるHeaderが違うなんて事があるならこれで。
$ curl -i -X POST http://example.com/
-I
オプションだと、HTTP HeaderだけでBodyが見られないので-i
オプションの方が便利かも。
sedコマンドの使い方
-e
は省略可能
$ sed -e 's/foo/bar/' $ sed 's/foo/bar/'
デリミタは変更可能
$ sed 's|http://|https://|'
正規表現である
$ sed 's| HTTP/1\.[0-1]||'
デリミタ色々
$ sed 's|foo|bar|' # | $ sed 's=foo=bar=' # = $ sed 'sAfooAbarA' # A $ sed 's(foo(bar(' # (
使う機会はほぼ無いと思うけど、やってみたら*3英字とかも出来た。
$ sed 's(foo)(bar)' # ダメ
残念ながらPerlのように括弧を括弧的なデリミタとして使う事は出来ないみたい。
行を狭める
例)
1行目だけを置換したい場合
$ sed '1s/linux/リナックス/g' ファイル名 > 出力先ファイル名1〜10行目だけを置換したい場合
$ sed '1,10s/linux/リナックス/g' ファイル名 > 出力先ファイル名2行目から最終行までを置換したい場合
$ sed '2,$s/linux/リナックス/g' ファイル名 > 出力先ファイル名1行目から先頭がlではじまる行までを置換したい場合
$ sed '1,/^l/s/linux/リナックス/g' ファイル名 > 出力先ファイル名先頭がlではじまる行だけを置換したい場合
$ sed '/^l/s/linux/リナックス/g' ファイル名 > 出力先ファイル名先頭がlではじまる行以外を置換したい場合
http://www.nurs.or.jp/~sugi/sed.htm
$ sed '^t/!s/リナックス/g' ファイル名 > 出力先ファイル名
こんな事も出来るらしい。
一括置換
$ find . -type f -print0 | xargs -0 sed -i -e 's/foo/bar/g' $ find . -type f -print0 | xargs -0 perl -pi -e 's/foo/bar/g' # $ find . -type f | xargs sed -i -e 's/foo/bar/g' # $ find . -type f | xargs perl -pi -e 's/foo/bar/g'
-print0
、-0
についてはMacでfindとxargsをパイプで繋いで使うなら -print0 と -0 を必ず使うメモ - kanonjiの日記を参照。
findで除外
$ find . ! -name "*.svn*" -a -name "*.html"
.svnフォルダを除外 and *.html。ただし、厳密に.svnフォルダに絞れているかは疑問。foo.svn.htmlなんてファイルがあったら混ざるかも。
$ find . ! -path "*.svn*" -a -name "*.html"
案の定漏れてたので改めて調べて-path
を見つけました。
cutコマンドで空白をデリミタにする
$ cut -d' ' -f1,3 foo.log
GNU Screen中に画面が固まったら復帰できる場合がある
C-a C-q
これは、元々C-a C-s
で画面を固定できるが、知らないうちにやってしまった場合に、復帰するためのC-a C-q
を試してみるというだけの事。
ASCII制御コード | 信号 | GNU Screenで入力 | Terminalから入力 |
DC1 | XON | C-a C-q |
C-q |
DC3 | XOFF | C-a C-s |
C-s |
別にGNU Screenの機能という訳ではなく、ASCII制御コードのDC1, DC3に対してよくある動きらしい。例えばtop
コマンドを動かしてる際にC-s
を入力すると、画面が固定される。あらゆる状況でそうなるという訳じゃないと思うけど。この辺まだちゃんと把握できてない。
C-a
はGNU Screenのコマンド文字。
コマンドをグルーピングする
$ { cat 20120601.log; cat 20120602.log; } | grep foo
波括弧でコマンドのグルーピングが出来る。
{ cat 20120601.log; cat 20120602.log; } #OK { cat 20120601.log;cat 20120602.log;} #OK {cat 20120601.log; cat 20120602.log; } #NG
何故か左の波括弧とコマンドの間のスペースは、無くすとエラーになります。あと最後のコマンドの後ろの;
*4も必須。
make -n installでdry run
$ man make [snip] -n, --just-print, --dry-run, --recon Print the commands that would be executed, but do not execute them. [snip]
dry runでinstall時にどこにファイルが配置されるか、インストール前に確認できる。
curlでリジューム
$ curl -C - -o foo.tar.gz http://www.example.com/foo.tar.gz ** Resuming transfer from byte position 772428440 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 77.4M 100 77.4M 0 0 326k 0 0:04:03 0:04:03 --:--:-- 163k
こんな感じでリジュームできます。不安定な回線でちょっとでかいファイルをダウンロードしないとならない時なんかに活躍。
なお-C 10
だと、ファイルの頭から11byteからリジュームらしい。
curlでPOST, PUT, DELETE
# GET $ curl http://localhost:3000/users.xml $ curl http://localhost:3000/users/3.xml # POST $ curl http://localhost:3000/users -X POST -d "user[name]=postman" -d "user[age]=19" # PUT $ curl http://localhost:3000/users/4 -X PUT -d "user[name]=putman" -d "user[age]=20" # DELETE $ curl http://localhost:3000/users/5 -X DELETEcurlコマンドからのRESTなリクエストを送り方 - ちくわプログラマにっき
curlでCookie
$ curl -c foo.txt http://www.example.com/ #Cookie保存 $ curl -b foo.txt http://www.example.com/ #Cookie送信 $ curl -b "foo=bar; baz=qux;" http://www.example.com/ #Cookie送信
大体こんな感じ。
$ curl --cookie-jar foo.txt http://www.example.com/ #Cookie保存 $ curl --cookie foo.txt http://www.example.com/ #Cookie送信
一応、オプションをフルネームで書くとこうなる。
git grepの様にフォルダ内をgrepする
$ grep foo -r . $ find . -type f -print0 | xargs -0 grep foo
find xargs grep
でやってたけどgrep
の-r
オプションがすごい便利です。find xargs grep
の方はMacでfindとxargsをパイプで繋いで使うなら -print0 と -0 を必ず使うメモ - kanonjiの日記という事もあって、コマンドが長くなって割とめんどくさい。
マッチしたファイル名のリストを取得
$ grep foo -r . -l
単にgrep
の-l
オプションってだけだけど、忘れがちなのでメモしておきます。
一部除外する
$ grep --exclude=.svn foo -r .
psコマンドでとにかく全情報を出力する
$ ps aux
$ ps auxf #ツリー構造で表示。Macだと使えない。
a | 全ユーザーのプロセスを表示 |
u | ユーザー名やその他詳細な情報を表示 |
x | 制御端末の無いプロセスを表示 |
grepのハイライトをパイプしたlessでもハイライトする
$ grep foo --color=always | less -R
--color=auto
でも行けるっぽい情報も有ったけど、自分の環境では--color=always
じゃないとだめだった。
curlでajaxアクセスを装う
$ curl -H "X-Requested-With: XMLHttpRequest;" http://example.com
単にヘッダーに追加しているだけなんだけど、jQuery等を使うと、この拡張ヘッダーがつくらしいので、手動でつける事でajaxアクセスを装う。ヘッダーに追加する以外は普通のアクセスなのでただ付けるだけなんだけど。
Macでポートを使っているプロセスを調べる
$ lsof -i :3306 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME mysqld 16099 myuser 12u IPv4 0xffffff8026416c00 0t0 TCP *:mysql (LISTEN) MySQLWork 40355 myuser 22u IPv4 0xffffff80189f3160 0t0 TCP localhost:51146->localhost:mysql (CLOSED)
多分Mac専用。
環境変数とシェル変数を一覧
$ printenv #環境変数の一覧 $ set #シェル変数の一覧 $ printenv TERM #TERMの値だけ表示
HDD全域からファイルをfindする
$ find / -name foo.log 2>/dev/null
Permission denied が鬱陶しいので、標準エラーを捨てる。
ファイルのmd5 sha1ハッシュ値を求める
$ md5sum foo.txt $ sha1sum foo.txt $ sha1sum foo.txt bar.txt #複数指定 $ sha1sum *.txt #ワイルドカード # Mac OS X $ md5 foo.txt $ openssl sha1 foo.txt
MacはLinuxと使えるコマンドが違う様子。
複数指定やワイルドカードは、たまたま調べたところに書いてあったのでsha1sum
以外でも使えるかしらない。
2007年現在、SHAは生成するビット長が異なるSHA-1 (160ビット)、SHA-224、SHA-256、SHA-384、SHA-512の5種類が存在している。
Secure Hash Algorithm - Wikipedia
グループのメンバーで1993年にはじめに発表されたものは、公式にはSHAと呼ばれている。しかしその後のものと区別するためにしばしばSHA-0と呼ばれている。2年後、SHAに初めての後継となるSHA-1が発表された。さらにSHA-224、SHA-256、SHA-384、SHA-512と4つの変形が、増加する出力の範囲とわずかなデザインの違いで発行されている。それらはしばしばまとめてSHA-2といわれている。
Secure Hash Algorithm - Wikipedia
shaって名前紛らわしいので、メモ。
標準入力をコマンドに渡す
$ echo 'foo' | example $ example <<_EOT_ foo bar _EOT_
example foo.txt
の様に、ファイルをオプションに取るコマンドが有るとして、ファイルを作らずに内容だけコマンドに渡すには、標準入力が使えたりします。echo
をパイプするのは直ぐ思いついたけど、改行を含むなら、ヒアドキュメントをリダイレクトする方法が使える。
リダイレクト (CLI) - Wikipedia
まさかこういう情報をWikipediaで見つけるとは思ってなかった。
ヒアドキュメント内のシェル変数を展開しない様にする
#「$」を表示したいときは「\$」のようにエスケープする cat <<_EOT_ ヒアドキュメント中では変数も使用できます。 \$1 は $1 です。 _EOT_ # 終了文字をエスケープするとヒアドキュメント中の変数は展開されない cat <<'_EOT_' シングルクオートで終了文字を囲むと変数は無視されます。 \$1 は $1 です。 `echo "コマンド置換も無視されます。"` _EOT_ cat <<\_EOT_ バックスラッシュでも同様です。 \$1 は $1 です。 `echo "コマンド置換も無視されます。"` _EOT_入力と出力 | UNIX & Linux コマンド・シェルスクリプト リファレンス
ヒアドキュメント内では、シェル変数が使えるため$
をそのまま文字として扱いたい場合、上記2つの方法で出来るとの事。
gccでよく使うオプション、らしい
標準入力と標準出力を同時にリダイレクトする
wc -l < foo.log > /tmp/log-line-count
foo.logを標準入力にリダイレクトしてwc
に渡し、その結果の標準出力を/tmp/log-line-count
にリダイレクトして書き込んでます。
文字列内でコマンド実行
$ echo "foo`echo .`bar" $ echo "foo$(echo .)bar"
どちらもfoo.bar
と出力。
$ echo 'foo`echo .`bar' # foo`echo .`bar $ echo 'foo$(echo .)bar' # foo$(echo .)bar
シングルクォートだと実行されない。
kshやbashの場合、「$(コマンド)」($+単一の丸括弧)はバッククォート指定「`コマンド`」と同じ。
http://www.ne.jp/asahi/hishidama/home/tech/unix/sh.html#backquote
$()が使えるシェルなら、バッククォートよりも$()を使うべき。(バッククォートは古い形式であり、ネストできないし、開始と終了もまぎらわしい)
バッククォートよりも$()
が推奨される。
echo $(cd $(dirname $0);pwd)
http://unoh.github.io/2008/09/02/bashtips.html
$()
でのネストの例。
関数の有無で分岐
$ type __git_ps1 > /dev/null 2>&1 && echo ok # okが出力 $ type __git_ps1_ > /dev/null 2>&1 && echo ok # 出力されない
Bashでコマンドの存在チェックはwhichよりhashの方が良いかも→いやtypeが最強 - Qiita
シェルスクリプトでif文の場合
if type __git_ps1 > /dev/null 2>&1 ; then # Do something. fi
標準出力、標準エラーは捨てて、終了ステータス(exit-status)で判別するんだと、思う。
関数の有無じゃないけど、ちょっと似てる事という事でtestコマンド使ってcron
0 0 * * * /usr/bin/test $( date -d '+1 day' +\%d ) -eq 1 && /home/hoge/cron/foo.sh↑で、毎月月末日の零時にfoo.shが実行されるようになります。
http://qiita.com/yadok/items/5c99cecdb17a436351f2
wcの結果から空白を取り除く
$ cat file | wc -l | td -d ' '
wc
は行数の前に幾つかの空白が入るので、場合によっては邪魔になります。その空白をtd
で取り除きます。
変数に入れた改行を出力する
$ FOO=$(ls -1) $ echo $FOO foo bar baz $ echo "$FOO" #ダブルクォートで囲むと改行が出力される foo bar baz
findしたファイルをパイプで別コマンドに1個ずつ渡したい
$ find . -type f -name *.csv | while read f; do some_command $f; done
パイプ出力を現在のシェル上のwhileに喰わせる上手いやり方 - Qiita
ちなみに、別コマンドに渡すんじゃなくて変数に入れるような場合は、whileがサブシェルで実行されてしまうらしく、whileの中で変数に入れても、消えてしまうらしいです。
vmstatに日時を付けてファイルに出力する
$ vmstat 1 | gawk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0 } { fflush() }' >> vmstat.log $ vmstat 1 | awk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0 } { system(":") }' >> vmstat.log
なぜかはわからないのだが、ファイルへの書き込みが、パイプ後ろのプロセス(上記なら awk や grep)が終了してから行われているようだ。なので、3秒おきに10回出力した結果は、awk が正常終了した後に、ファイルへ書き込まれる。途中で vmstat を強制終了した場合には、ファイルへは何も書き込まれない。
[snip]
gawk で、fflusu() 関数を使えばパイプがリフレッシュされるとのことで、次のようにしたらうまくいった。
# vmstat -n 3 | gawk '{ print strftime("%Y/%m/%d %H:%M:%S"), $0 } { fflush() }' >> vmstat.log
awk でも、system() 関数を使えばパイプがリフレッシュされるとのことで、(ちょっときたないが)次のようにしたらうまくいった。
# vmstat -n 3 | awk '{ print strftime("%Y/%m/%d %H:%M:%S"), $0 } { system(":") }' >> vmstat.log
(今さら) vmstat の結果に時間をつけてファイルに出力する - あしのあしあと