トップページunix
987コメント345KB

シェルスクリプト総合 その13

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。2008/10/16(木) 00:48:38
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>1-6くらい)をご覧ください。


□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
 bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
 Linuxユーザは/bin/shの正体がbashなので特に注意。
・csh/tcshのシェルスクリプトは推奨されません。
(理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
 manや参考リンクを見ましょう。
 aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)

□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
 RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。

前スレ
シェルスクリプト総合 その12
http://pc11.2ch.net/test/read.cgi/unix/1218277263/
0210名無しさん@お腹いっぱい。2008/11/15(土) 11:21:21
そしてstderrを自由にリダイレクトできないcsh批判へ
0211名無しさん@お腹いっぱい。2008/11/15(土) 12:47:14
できればいいじゃん
0212名無しさん@お腹いっぱい。2008/11/15(土) 13:08:04
csh ? なんですだそりゃ?
0213名無しさん@お腹いっぱい。2008/11/15(土) 13:18:37
標準エラー入力を新設するべきだ。

hoge | less

ってやった時、lessは標準入力からパイプを読むが、
この時、less自体の操作のためにキーボードを読む必要があるが、
/dev/ttyを直接読まずに、「標準エラー入力」を読んだ方が美しいし応用も効く。
0214名無しさん@お腹いっぱい。2008/11/15(土) 13:50:32
キーボードを読む必要があるのなら、キーボードを読むべきじゃないの?

もしかして、エラー出力≒コンソール出力、って思ってるなら、
あんまりそういうことはないとだけ言っておく
0215名無しさん@お腹いっぱい。2008/11/15(土) 14:00:25
バックグラウンド起動したときに出るpidとかのメッセージは何出力ですか?
0216名無しさん@お腹いっぱい。2008/11/15(土) 14:14:26
>>215
$ : & > /dev/null
とか
$ : & 2> /dev/null
とかやってみて確かめればいいだろ。
0217名無しさん@お腹いっぱい。2008/11/15(土) 14:33:04
>>216
それだと : の stdout や stderr が /dev/null になるんじゃない?

exec 2>/dev/null
: &

とかしないと
0218名無しさん@お腹いっぱい。2008/11/15(土) 14:48:01
>>216
[root@migii ~]# : & > /dev/null
[1] 2420
[root@migii ~]# : & 2> /dev/null
[2] 2421
[1] Done :
[root@migii ~]#
0219名無しさん@お腹いっぱい。2008/11/15(土) 16:09:56
>>214
無端末状態で lessを起動しようとすると、not a tty って言って拒否されるけど、
標準エラー入力があれば、/dev/tty をじか読みしないから起動できると言う
メリットがある。

「キーボードを読む必要がある」のじゃなく、
「最終的にキーボードにつながっているはずのパイプとかソケットとか」
を読むための「標準エラー入力」
0220名無しさん@お腹いっぱい。2008/11/15(土) 16:13:48
AEGISにはあったな。
0221名無しさん@お腹いっぱい。2008/11/15(土) 16:17:52
>>214 は知ったかだな。
コンソールとTTYもまた別物だし。
何が、"言っておく" だ。
0222名無しさん@お腹いっぱい。2008/11/15(土) 16:23:29
>>219
controlling terminalを知らない人?
0223名無しさん@お腹いっぱい。2008/11/15(土) 16:26:11
>>222
もちろん知ってるよ。
知った上で言ってるよ。

制御端末はどちらかと言うとプロセス管理上の問題(シグナルとか)だから、
今の話とはちょっとずれてる。
制御端末がなくても標準エラー入力でlessは動作可能。
0224名無しさん@お腹いっぱい。2008/11/15(土) 16:31:07
>>222 は、controlling terminal と pseudo terminal を混同してる悪寒。

pseudo terminalだったとしてもlessにとって必須というわけじゃないしなぁ。
パイプのような dumb入力でも動作可能。
0225名無しさん@お腹いっぱい。2008/11/15(土) 16:36:03
どうでもいいが、仮名にしても標準エラー入力でなく
もうちょっとマシな命名してくれよ。
0226名無しさん@お腹いっぱい。2008/11/15(土) 16:41:05
標準エラー出力に対するものだから標準エラー入力と言ってるだけで、
今から命名するなら「標準診断入力/出力」とかだろな。
0227名無しさん@お腹いっぱい。2008/11/15(土) 16:45:41
>>219
何がやりたいのか不明。
0228名無しさん@お腹いっぱい。2008/11/15(土) 18:24:10
ファイルのタイムスタンプを、引数指定の秒数(または分や時間)だけ
相対的に進める(または遅らせる)ようなシェルってどう書きますか?

touchやlsを駆使すればできそうですが、なるべく奇麗な方法でよろしこ。
0229名無しさん@お腹いっぱい。2008/11/15(土) 18:30:10
touch -A
0230名無しさん@お腹いっぱい。2008/11/15(土) 18:50:52
>>229
それ、どこのtouchだよw
0231名無しさん@お腹いっぱい。2008/11/15(土) 19:27:47
>>228
GNU dateで、
touch --date=`date --date='1 year ago'` filename
0232名無しさん@お腹いっぱい。2008/11/15(土) 19:35:12
>>231
それだと、「現在時刻」からの相対時刻になっちゃうじゃん
質問は元のファイルの時刻からの相対
0233名無しさん@お腹いっぱい。2008/11/15(土) 19:48:57
結局>>215はなんなの?
0234名無しさん@お腹いっぱい。2008/11/15(土) 19:53:03
>>233
シェル自体の標準エラー出力だよ。
だから、コマンド起動時に単純に 2> /dev/null とかでリダイレクトできないから
わかりにくいだけ。
0235名無しさん@お腹いっぱい。2008/11/15(土) 20:00:00
補足すると、>>217 の言うように、exec 2>/dev/null すれば確かめられる。
ただし、exec 2>/dev/null した瞬間からシェルのプロンプトも
表示されなくなるので、操作困難になる。
ついでに、シェルのプロンプトも標準エラー出力というわけだ。
0236名無しさん@お腹いっぱい。2008/11/15(土) 20:00:58

$ find . -maxdepth 1 -name '*foo*' | xargs mv dir/

のようにして '*foo*' にマッチしたファイルを dir/ 下に移動したいんですが、パイプ
からの出力がdir/ の後ろに位置してしまい、
$ mv dir/ $files
のように解釈されてしまう為、うまくいきません。

$ mv $files dir/
のように解釈させるにはどうすればいいですか?
0237名無しさん@お腹いっぱい。2008/11/15(土) 20:05:16
-i {} dir
0238名無しさん@お腹いっぱい。2008/11/15(土) 20:12:26
>>237
できました。ありがとうございました。
0239名無しさん@お腹いっぱい。2008/11/15(土) 20:14:08
>>238
どこの xargs つかってるの?
0240名無しさん@お腹いっぱい。2008/11/15(土) 20:22:29
-exec涙目
0241名無しさん@お腹いっぱい。2008/11/15(土) 20:44:58
xargsはobsolete

-exec mv {} dir +
0242名無しさん@お腹いっぱい。2008/11/15(土) 20:51:42
-exec sh -c 'mv "$@" OOO' dummy {} +
0243名無しさん@お腹いっぱい。2008/11/15(土) 22:24:25
>>234 >>235
ありがと
結局これを普通にリダイレクトは無理ということ?
0244名無しさん@お腹いっぱい。2008/11/15(土) 22:28:44
>>243
もし、& 付けた後の pid表示が邪魔だから消したいという話なら、

$ (command &) 2> /dev/null

で消せるよ。
実は、

$ (command &)

だけでも消えるんだけどね。
0245名無しさん@お腹いっぱい。2008/11/16(日) 01:59:13
今使ってるシェルを知るには$SHELLを見ればいいって言われたんだけど
bashからcshに変えても値が/bin/bashのままなんだけど・・
0246名無しさん@お腹いっぱい。2008/11/16(日) 09:37:17
>>245
cshはバカだから$shell。
% set
% setenv
すれば、一覧が見れる。
0247名無しさん@お腹いっぱい。2008/11/16(日) 09:54:28
>>246
thx
0248名無しさん@お腹いっぱい。2008/11/16(日) 10:17:00
>>228 の解答まだぁ?
0249名無しさん@お腹いっぱい。2008/11/16(日) 10:20:41
kshって色づけ出来ないの?
0250名無しさん@お腹いっぱい。2008/11/16(日) 10:41:22
cshは、もはや継続行のコメントアウト部分のみしか羨ましくない
0251名無しさん@お腹いっぱい。2008/11/16(日) 22:08:14
>>228,248
つ touch -d @`stat -c %Y hogehoge | xargs expr -3600 +` hogehoge

$ touch hogehoge
$ ls -l hogehoge
0 -rw-r--r-- 1 xxx users 0 Nov 16 22:05 hogehoge
$ sudo touch -d @`stat -c %Y hogehoge | xargs expr -3600 +` hogehoge
$ ls -l hogehoge
0 -rw-r--r-- 1 xxx users 0 Nov 16 21:05 hogehoge

ただしGNU coreutils使用。
0252名無しさん@お腹いっぱい。2008/11/16(日) 22:20:22
>>251
GNUありでいいならもっと簡単にできるだろ。
0253名無しさん@お腹いっぱい。2008/11/16(日) 23:23:50
うぉ -r ってのがあるのね・・・アリガトン>252
0254名無しさん@お腹いっぱい。2008/11/16(日) 23:51:58
なぜsudo?
0255名無しさん@お腹いっぱい。2008/11/17(月) 00:25:30
あれ、ホントだ。たぶんchownと脳と指が取り違えて打ってた。
この癖はリアルで危険だから直さんといかんな・・・
0256名無しさん@お腹いっぱい。2008/11/17(月) 00:35:33
キ違いに刃物
0257名無しさん@お腹いっぱい。2008/11/17(月) 07:26:21
>>218>>251
先週末はルート祭だったのね。
0258名無しさん@お腹いっぱい。2008/11/17(月) 22:10:51
教えてください。

#!/bin/sh

TestFunc()
{
echo $1 # ここでは ls -l "aaa bbb"
$1 # ここでは ls -l aaa bbb と処理されてしまう
}

TestFunc "ls -l \"aaa bbb\""

Bシェルで関数に引数を与え、コマンドを実行することを
考えています。
コマンドの引数にスペースつきのものを含む場合、ダブルコーテーションで
くくっていても、実行される場合は外されてしまうようです。

そもそもechoで出した場合は正しく表示されるのに、実行した場合
ダブルコーテーションが外れてしまう理由も良く分からないのですが、
どのようにすれば正しく実行できるのでしょうか?

TestFuncc()
{
$1 $2 "$3"
}

TestFunc "ls" "-l" "aaa bbb"

とすれば良いのは分かるのですが、コマンドの引数が変わった場合に対応できないので
汎用性が落ちますし、出来れば一つの文字列で関数に渡したいのです
0259名無しさん@お腹いっぱい。2008/11/17(月) 22:16:57
>>258
TestFunc()
{
echo "$@"
"$@"
}
0260名無しさん@お腹いっぱい。2008/11/17(月) 22:30:13
>>259
TestFunc()
{
echo "$@"
eval "$@"
}
だろ?
0261名無しさん@お腹いっぱい。2008/11/17(月) 22:36:36
-a
とか
*
とかよりも素人には消すのが難しいファイル名ってありますかね
0262名無しさん@お腹いっぱい。2008/11/17(月) 22:37:22
ありがとうございます。
>>259
は既に試してみましたがダメでした。

>>260
は、今環境が無いので、明日会社で確認してみます。
0263名無しさん@お腹いっぱい。2008/11/17(月) 22:40:51
この場合は$@なの?
$*じゃだめなのkすら
0264名無しさん@お腹いっぱい。2008/11/17(月) 22:57:29
>>263
駄目です。"aaa bbb"を分解したくないなら。
>>261
文字化け系
0265名無しさん@お腹いっぱい。2008/11/17(月) 23:10:51
>>264

文字化け系は、取り合えず消したくないファイルを
別のディレクトリに退避して、rm TAB{印字可能文字}*とかで、何とかなる。
・・なってほしい。
0266名無しさん@お腹いっぱい。2008/11/17(月) 23:57:28
文字化け系のファイルがいっぱいあると、
消したくないファイルの特定すら面倒だし、間違う可能性もある。
0267名無しさん@お腹いっぱい。2008/11/18(火) 01:47:14
*って消しにくいの? rm * でまっさきに消えるじゃん
普通の操作で消去できないファイルを作るのは ".[ファイル名]" にするのが常套手段

名前を厳密に指定しない限りrmでは消せないし
0268名無しさん@お腹いっぱい。2008/11/18(火) 02:05:18
どこが常套手段なんだろう。意味不明。
0269名無しさん@お腹いっぱい。2008/11/18(火) 02:07:49
第一消せるし。zshならGLOB_DOTS。
そんな挙動を前提にrm *とかやってると痛い目を見るぞ。
0270名無しさん@お腹いっぱい。2008/11/18(火) 02:42:45
>>261
rm -i * とされると rm -- -a や rm \* や rm '*' なんて知らなくても、文字化け系でも大抵何とかなる
先に必要なファイルをあらかた退避したら、作業もそう面倒でもない

ちょっとした嫌がらせ?部下に勉強させたい?なら .* とか
^Ha (スペース+制御文字^H+a) として普通に ls だと a にしか見えない、rm a でも rm a* でも消えない、とかかな
0271名無しさん@お腹いっぱい。2008/11/18(火) 05:43:00
zshでタブキーをぱかぱか押して補完させれば大体なんとかなる
0272名無しさん@お腹いっぱい。2008/11/18(火) 08:06:20
>>262
>今環境が無いので、明日会社で確認してみます。

シェルの環境がないって? どんな環境?
まさか、自宅にはWinしかないとか?
そんな人に解答したくないね。
ここはみんな、UNIXからアクセスしている人のみのはず。
0273名無しさん@お腹いっぱい。2008/11/18(火) 08:23:42
しょうもない妄想乙
0274名無しさん@お腹いっぱい。2008/11/18(火) 10:06:07
>>271
そしてたまにzshが落ちる、と。
わかります。
0275名無しさん@お腹いっぱい。2008/11/18(火) 11:19:57
>>272
お前は解答しなくていいよ。迷惑だから。
0276名無しさん@お腹いっぱい。2008/11/18(火) 23:33:31
>>272
winてなに?おいしいの
0277名無しさん@お腹いっぱい。2008/11/19(水) 01:56:35
携帯電話でそんなのがあるらしいぞ
0278名無しさん@お腹いっぱい。2008/11/19(水) 07:03:16
ファイルの先頭行だけを表示しない方法ってありますか?

--------------
$ cat hoge
aaa
bbb
ccc
--------------
こういうファイルがあるとして、先頭行だけを表示しないようにしたい。
awkを使って、以下のようにできるけど、もっとスマートにしたい。
$ cat hoge | awk '{if (NR > 1) print}'

イメージ的にはこんな感じで。
$ cat hoge | cutline 2-





0279名無しさん@お腹いっぱい。2008/11/19(水) 07:16:37
>>278

tail -n +2 hoge
0280名無しさん@お腹いっぱい。2008/11/19(水) 07:35:05
>>278
sed 1d hoge
0281名無しさん@お腹いっぱい。2008/11/19(水) 08:16:42
>>278
「もっとスマートにしたい」というなら、
まずは自分で書いてる無駄な cat が無駄であることに気づけw

>>279 に補足すると、tailの古いバージョンでは
tail +2 hoge
0282>>2782008/11/19(水) 08:18:35
>>279->>281
神! ありがとー

0283名無しさん@お腹いっぱい。2008/11/19(水) 08:23:09
>>278
awk使うにしても、if文が無駄だな。

awk 'NR > 1 {print}' hoge
0284名無しさん@お腹いっぱい。2008/11/19(水) 13:15:52
>>283
awk 'NR > 1' hoge
0285名無しさん@お腹いっぱい。2008/11/27(木) 07:43:58
grepで質問です!!

以下のような制御(色)文字を含んだファイルがあるとします。("生データ"とよぶことにします)
$ cat -t hoge.dat
^[[0;31mhello^[[0mend

catコマンドで表示するとこんな感じになります。("表示データ"とよぶことにします)
$ cat hoge.dat
helloend

で、"表示データ"をgrepするために以下のようにしたのですが、うまくひっかけることができません。
$ grep ^hello hoge.dat

grepのaオプションも使ってみたのですが、だめでした。
表示データをgrepする方法で、いい方法を教えていただきたく。

よろしくお願いします。

0286名無しさん@お腹いっぱい。2008/11/27(木) 07:58:33
>>285
stringsで抜き出したものをgrepするとか。
0287名無しさん@お腹いっぱい。2008/11/27(木) 08:07:10
>>285
単に、grep hello する。(^なし)
あるいは、grep mhello


>>286
そういう問題じゃないだろ。[0;31m とかはテキストだから。
0288名無しさん@お腹いっぱい。2008/11/27(木) 08:37:23
「行頭」とかをちゃんと区別したいなら、
エスケープシーケンス(^[からアルファベットまで)をちゃんと除く必要がある。
カーソル移動とかあれば、行頭って何って話になるけど。

sed 's/^[[^a-zA-Z]*[a-zA-Z]//' hoge.dat | grep ^hello
^[ は当然エスケープ文字な。
0289名無しさん@お腹いっぱい。2008/11/27(木) 08:40:43
>>288
あほか。それだとエスケープシーケンス中の数字やセミコロンに対応してない。
仮に英文字だけのシーケンスだとしても、hello自体まで削除される。
0290名無しさん@お腹いっぱい。2008/11/27(木) 08:53:39
いや、>>288 で合ってる。
エスケープ自体をsedに入れるのに難があるけどな。
0291名無しさん@お腹いっぱい。2008/11/27(木) 08:56:57
馬鹿をさらした >>289 は何をどう読み違えたんだ?
0292名無しさん@お腹いっぱい。2008/11/27(木) 09:42:14
あほか?
エスケープシーケンスは端末依存なので、それを解釈する端末エミュレーションも実装しないとだめ。
まぁ、がんばってくれ。
0293名無しさん@お腹いっぱい。2008/11/27(木) 09:47:53
>>292
あほか。
エスケープシーケンスは、
ESCで始まり、英文字以外が0文字以上続いた後、英文字1文字で終る、
ということは決まっている。
端末(TERM)が変わって、具体的なシーケンスが変わっても、
シーケンス自体の規則は変わらない。
だから、すべてのシーケンスを削除するのが目的なら、
>>288 でよい。
0294名無しさん@お腹いっぱい。2008/11/27(木) 09:49:43
というか、>>288 の sed に g 付けとけよな。凡ミス指摘な。
0295名無しさん@お腹いっぱい。2008/11/27(木) 09:54:26
馬鹿をさらしたあと、>>292 で馬鹿の上塗り?
02962882008/11/27(木) 09:55:51
なんかあほばか呼ばわりされて白熱してるとこすまんが、g 付け忘れた。
「行頭」だけなら最初のシーケンス消せばいいだけだからなくても動くけど。

0297名無しさん@お腹いっぱい。2008/11/27(木) 11:06:42
>>293
hp端末の制御文字列はエスケープシーケンスと認めてもらえないんでしょうか。
0298名無しさん@お腹いっぱい。2008/11/27(木) 13:38:37
>>293, >>295
あほ。カーソル移動含むエスケープシーケンス含んでたらどうすんだよ。
0299名無しさん@お腹いっぱい。2008/11/27(木) 14:36:21
>>298
カーソル移動のエスケープシーケンスも、
>>293 の言う範囲に含まれる。端末によらず。
0300名無しさん@お腹いっぱい。2008/11/27(木) 14:50:14
>>299
あほ。カーソル移動して文字列を逆順に出力してたらどうやってgrepすんだよ。
0301名無しさん@お腹いっぱい。2008/11/27(木) 14:55:29
ツマラナイカラヤメロ
0302名無しさん@お腹いっぱい。2008/11/27(木) 14:57:43
>>298 >>300
馬鹿の上塗りの上塗りの上塗りの上塗りw
0303名無しさん@お腹いっぱい。2008/11/27(木) 15:17:49
>>302
知能の足りなさを認められない、あほ。惨め。
0304名無しさん@お腹いっぱい。2008/11/27(木) 15:27:01
>>303
カーソル移動の件に関しては
>>288 が一番最初に断ってるのだが、読み落したかい?
さも、>>300 で自分が最初に発見したみたいに書き込んでるけどさw
0305名無しさん@お腹いっぱい。2008/11/27(木) 15:38:01
>>304
未だに理解できてない>>302に言ってやってくれ。ww
0306名無しさん@お腹いっぱい。2008/11/27(木) 17:53:24
tcl の文法が嫌いなので expect を使いたくないのですが、
その代用として、同様のツールがあれば教えてください。
0307名無しさん@お腹いっぱい。2008/11/27(木) 18:01:39
pexpect
0308名無しさん@お腹いっぱい。2008/11/27(木) 18:06:23
expect.rb
0309名無しさん@お腹いっぱい。2008/11/27(木) 18:15:52
>>307
> pexpect
ありがとうございます! かなり良さ気ですね。
それに python は大好きなので、是非それを使ってみようかと思います。
■ このスレッドは過去ログ倉庫に格納されています