シェルだけで、ファイル名だけ変更、またはファイルを一括指定
ファイルパス展開で{a,b,c}記法を使うと、パスの一部(例:ファイル名)だけが違う複数ファイルを簡単に指定できます。
mv /the/long/long/path/to/file /the/long/long/path/to/new_file
これが
mv /the/long/long/path/to/{file,new_file}
と簡単にできます。zshなら補完も可能です。
ファイル以外でも下記のようにテキストを展開することができます。
$ echo hoge{fuga,piyo,muga}
hogefuga hogepiyo hogemuga
シェルだけで、連番のファイルをまとめて選択
ファイルパス展開で[012]記法を使うと、連番のファイルを選択することができます。
cat /blah1 /blah2 /blah3 /blah4
これが
cat /blah[1234]
と簡単にできます。
(存在しないファイルはスキップされます。)
シェルだけで、落ちても自動で再起動
while true; do target_script; sleep 1; done
終了する際はCtrl-Cを連打してください。
シェルだけで、forループのワンライナー
(これは基本かもしれませんが、なんだかんだで重宝します・・)
for i in {1..100}; do target_script $i; done
(sedだけど)シェルだけで一括置換
sed -iを使うと、ファイルの中身を直接書き換えることができます。
例えば、dictionaryをdictonaryとtypoしてしまったケースがたくさんあるとすると、下記のコマンドで置換できます。(必ずgit等で前の状態に戻せるようにしておいてください!)
sed -i '' -E 's/(d|D)ictonary/\1ictionary/g' **/*.[mh]
-i ''
は、置換結果を元のファイルに書き出すオプションです。-i '.new'
とすれば、入力ファイル.newのように、.newが末尾についたファイル名で保存されます(=上書きされません)。
-Eは高度な正規表現を有効にするためのオプションです。
ファイル数が多い場合はagで絞ってから置換してもよいでしょう。
sed -i '' 's/some_bad_method_name_or_something/good_one/g' `ag -l some_bad_method_name_or_something ./lib`
下を.bashrcや.zshrcなどに貼っとくと便利です
sed-inplace () {
if (( $# < 2 )); then
echo "sed-inplace FROM TO [PATH ...]"
return 1
fi
from="$1"
to="$2"
shift 2
ag -l "$from" "$@" | while read file; do
if [ "`uname`" = "Darwin" ]; then # please, please give me portable sed...
sed -i '' -e "s/$from/$to/g" "$file"
else
sed -i'' -e "s/$from/$to/g" "$file"
fi
done
}
※ag/ackがない場合はgrep -Rで代用できますが、.gitが置換対象に含まれないよう注意してください
※Mac (BSD?)では-i ''
、Linuxでは-i''
と書く必要があります。
※()
が含まれているとsedが拾ってしまうので、\(
のようにエスケープしてください
シェルだけで、並列実行
gnu parallelコマンドを使うか、bashに内蔵されたバックグラウンド実行機能(&やbgコマンドを使うもの)+プロセスの終了待ちをするwaitコマンドを使えば簡単に並列実行できます。
parallel篇
cat url_list.txt | parallel wget
parallelコマンドは入力を改行で区切り、指定されたコマンドの後ろに付けて実行します。並列実行数はデフォルトでCPUコア数(スレッド数?)と同じですが、--jobsで指定もできます。
bashだけ篇
下記のコードはstackoverflowの引用です。 (Quoted from stackoverflow.)
#!/bin/bash
for i in {1 1000}
do
( Generating random numbers here , sorting and outputting to file$i.txt ) &
if (( $i % 10 == 0 )); then wait; fi # Limit to 10 concurrent subshells.
done
wait
さすがに最大ジョブ数で管理することはできず、10個立ち上げたら全部終わるのをまってから、また10個立ち上げて・・という流れになります。
(おまけ的な)シェルだけで、後置ならぬ前置if文や三項演算子っぽい何か
some_command && echo success!
some_command || echo fail...
some_command && echo success! || echo fail...
let cnt=0;
while ...; do
some_processing;
let cnt++;
(( $cnt >= 10 )) && break;
done
(おまけ2)xargsでシェルスクリプトを渡す
bash -cを使えばシェルスクリプトの文字列を直接実行でき、これとxargsを組み合わせればechoの中でバッククォート展開を叩いたりできます。
xargs -i
で{}がファイルパスに置き換わる(Mac OS X(おそらくBSDも)はxargs -I'{}'
と明示的な指定が必要)ます。
下記は「HogeClass」という文字が含まれているファイルが最後にcommitされた日を表示する例です。
ag -l 'HogeClass' | xargs -n1 -i bash -c 'echo "{}: `git log -n 1 --pretty=format:%cd -- {}`"'
※シェル芸というワードはこちらのtwitterアカウント名から頂きました