トップページunix
1001コメント327KB

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

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。2007/08/15(水) 07:25:02
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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 でトレースしましょう。

前スレ
シェルスクリプト総合 その8
http://pc11.2ch.net/test/read.cgi/unix/1171517324/
0579名無しさん@お腹いっぱい。2007/12/16(日) 15:21:47
>>578
日本語読めない低脳は引っ込んでいなさい。-regexの*の事ではない。

> ls /home/*/text/*.txt
> あたりが良いかなと思ったのですが、*は/も含むと聞いて困ってます。
0580名無しさん@お腹いっぱい。2007/12/16(日) 21:15:33
find -regex "...*..."
の場合、*は/を含む(ディレクトリ階層を縦断する)

ls */*
の場合、*は/を含まない(/で区切られたディレクトリ階層だけを探す)
0581名無しさん@お腹いっぱい。2007/12/16(日) 23:34:21
すみません。FreeBSDですが
文字列「aaa」と書いた1.txtをsedで「bbb」に変えて保存したい。
どのようにしたらいいでしょうか?
0582名無しさん@お腹いっぱい。2007/12/16(日) 23:38:27
sed -i -e 's/aaa/bbb/' 1.txt
05835812007/12/16(日) 23:51:33
>>582
-eが必要だったのか!でも-eは複数コマンドのオプションだと思ってた。
とにかくありがとう!
0584名無しさん@お腹いっぱい。2007/12/17(月) 01:04:43
たびたびすみません。FreeBSDですが
文字列「aaa\taaa」←水平タブ入りが書いてある1.txtを
文字列「bbb\tbbb」に変えて保存したい。
どうしたらいいでしょうか?
エスケープシーケンス入りの文字列の扱いがわからない。。。
0585名無しさん@お腹いっぱい。2007/12/17(月) 03:28:20
sed -i -e 's/aaa/bbb/g' 1.txt

タブ・エスケープは関係ない。/gをつけるとマッチしたもの全てを置換する(globalのg)。
gなしだと最初の一個だけ
05865842007/12/17(月) 05:11:44
>>585
じゃ、じゃあ

文字列aaaを

aaa
bbb

のように改行付きで置換したいとき

sed -i -e 's/aaa/aaa\nbbb/g' 1.txt
としても改行されません。
FreeBSDのsedはエスケープシーケンス使えない?
0587名無しさん@お腹いっぱい。2007/12/17(月) 06:24:56
% cat /tmp/1.txt
aaa
% sed -e 's/aaa/aaa\nbbb/g' /tmp/1.txt
aaa
bbb
% sed --version
GNU sed 4.1.1版

Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,
to the extent permitted by law.
(後略)
05885732007/12/17(月) 09:51:07
>>574
アップロードしてみました。
shellscript.tar.bz2
05895732007/12/17(月) 10:00:25
8が最後まで入ってなかったのと、まちがえて現行スレまで入れてしまったので、
アップロードし直した(shellscript_.tar.bz2)
0590名無しさん@お腹いっぱい。2007/12/17(月) 10:30:05
>>586
\を前置して改行をそのまま書く。

% echo aaa|sed 's/aaa/aaa\
bbb/'
0591名無しさん@お腹いっぱい。2007/12/18(火) 03:47:42
すいません。

scriptコマンドでコマンドログをとりたくて、ログイン時に自動的に呼び出されるよう
profileに書きましたが、ターミナルを終了する時にexitを何回も打たなくてはならないのが
気持ち悪いです。

例えば、一回のexit入力で、scriptとログインシェルの2回分を実行するというのは可能ですか?
0592名無しさん@お腹いっぱい。2007/12/18(火) 07:11:01
>>591
exec script
0593名無しさん@お腹いっぱい。2007/12/18(火) 07:42:32
>>592

ありがとう
0594名無しさん@お腹いっぱい。2007/12/18(火) 20:27:05
ファイルを読んでそのフィールドの一部分でuniqしたいんですけど、
どうすればよいですか?

APPLE,150円
APPLE,140円
APPLE,180円

とあったら、1フィールド目のみでuniqして先頭の行を出力したいです。
もちろん値段もほしいです。
ご教示お願いします。
0595名無しさん@お腹いっぱい。2007/12/18(火) 20:29:22
>>594
perl かなんかで書いちゃった方が早いんじゃね。
0596名無しさん@お腹いっぱい。2007/12/18(火) 20:31:18
awk 'BEGIN {FS=","} {if (foo != $1) {print}; foo = $1}'
0597名無しさん@お腹いっぱい。2007/12/18(火) 20:34:35
>595,596
早っ! ご教示ありがとございます
awkにします
0598名無しさん@お腹いっぱい。2007/12/18(火) 21:00:26
知ったかの >>595 が不憫。
0599名無しさん@お腹いっぱい。2007/12/18(火) 21:04:49
別に awk でできないとは言ってないよ。
0600名無しさん@お腹いっぱい。2007/12/18(火) 22:02:22
cat /tmp/file | perl -nle '$foo ne (@foo=(split/,/))[0] && (print, $foo=$foo[0])'
0601名無しさん@お腹いっぱい。2007/12/18(火) 22:25:21
久々に「catが無駄です」
0602名無しさん@お腹いっぱい。2007/12/18(火) 22:26:41
まあいいじゃん
0603名無しさん@お腹いっぱい。2007/12/18(火) 23:53:32
>>595
しね
0604名無しさん@お腹いっぱい。2007/12/18(火) 23:57:25
>>595=>>599
しね
二度と現れるなボケ
0605名無しさん@お腹いっぱい。2007/12/19(水) 00:46:05
awkがスクリプト言語と知らなかった598が顔を真っ赤にして暴れるスレ
06065952007/12/19(水) 00:54:10
なんかマズいこと言ったか?
よく知らないシェルスクリプトでがんばるより
便利で得意な言語で書いちゃった方が早いこともあるよ、
ってだけの話なんだけど。
0607名無しさん@お腹いっぱい。2007/12/19(水) 00:57:45
>>605
>>598じゃねーよw
おまえ、二度と現れるなと言っただろ?w
0608名無しさん@お腹いっぱい。2007/12/19(水) 01:01:44
>>595
おまえまだわかんねーのかよ?
おまえが言ってることは「ググレカス」と同レベル
どんな質問でも当てはまってしまうアホな回答。
0609名無しさん@お腹いっぱい。2007/12/19(水) 01:06:00
595じゃないが、>>608がなんで暴れてるのかよくわからん
0610名無しさん@お腹いっぱい。2007/12/19(水) 01:07:07
頭悪いからだろ。
0611名無しさん@お腹いっぱい。2007/12/19(水) 01:48:57
>>608じゃないが
>>595は自演が下手だな
こんな時間に過疎スレで1分後にレスって明らかに自演。
06125952007/12/19(水) 02:03:18
>>611
いや、>>595>>599>>606しか書いてないけど。
0613名無しさん@お腹いっぱい。2007/12/19(水) 02:19:31
perlには-aというオプションもあってだな。
0614名無しさん@お腹いっぱい。2007/12/19(水) 02:41:34
perlにはa2pという支援ツールがあってだな。
0615名無しさん@お腹いっぱい。2007/12/19(水) 02:49:04
awkのカーニハン本は言語の説明は1章だけで終わりで
あとは応用例だが、
perlのラクダ本は電話帳みたいな本が上下2巻。クックブックは別にある。
よってawkの勝ち
0616名無しさん@お腹いっぱい。2007/12/19(水) 02:57:18
perlは大体わかるけどawkはさっぱりです。
0617名無しさん@お腹いっぱい。2007/12/19(水) 03:12:02
>>615
awkの原典は、初学者が手にするとちょっとな。途方にくれるというか何というか。高い本なのに。
perlのラクダ本はその点は抜かりなく、初心者もすんなりと中に入り込んでいける。
awkの入門書で良書というと、ASCIIのawk256倍本くらいしか思いつかない。俺は今でも愛用してるけど、
あんな昭和の時代の本、いまどき手に入るはずもなく
0618名無しさん@お腹いっぱい。2007/12/19(水) 03:17:31
SED&AWKも忘れないで by おら
0619名無しさん@お腹いっぱい。2007/12/19(水) 03:49:30
>>618
その本初心者でもわかりやすい?
0620名無しさん@お腹いっぱい。2007/12/19(水) 10:07:59
>>594
perl -aF, -nle '$X{$F[0]} or print; $X{$F[0]} = 1'
0621名無しさん@お腹いっぱい。2007/12/19(水) 12:19:59
perlって見ためが汚いねw
0622名無しさん@お腹いっぱい。2007/12/19(水) 12:39:17
sedの置換について質問
タブ(\t)は置換できるのですが改行(\n)が置換できません。
例えば # cat a.txt
aaa
bbb
aaa(タブ)bbb

3行目の(タブ)区切りは置換できるけど1行目と2行目にマッチした文字を置換できません。
sedじゃ無理?こういうのawkでできたりしますか?
0623名無しさん@お腹いっぱい。2007/12/19(水) 12:47:27
>>622
sedについてはこちらへ

sed
http://pc11.2ch.net/test/read.cgi/unix/1085730992/
0624名無しさん@お腹いっぱい。2007/12/19(水) 12:56:24
cat /tmp/a.txt | awk '{sub("$", "<CR>"); sub("\t", "<TAB>"); print}'
0625名無しさん@お腹いっぱい。2007/12/19(水) 13:09:34
だから、catが(ry
ファイル名を前にもってきたいなら、せめて、
< /tmp/a.txt awk ...
と書け。
0626名無しさん@お腹いっぱい。2007/12/19(水) 13:21:07
>>554読んどけ。
0627名無しさん@お腹いっぱい。2007/12/19(水) 15:50:37
>>621
そうか?
0628名無しさん@お腹いっぱい。2007/12/19(水) 21:32:17
質問です。

a.txtの内容
----------
aaa
bbb
ccc
bbb
----------

このa.txtを
----------
aaa
bbb
ccc
ddd
----------
↑のようにa.txtを置換して保存したい。
この文字は何行目にあるか不明だとして
一番下のbbbをdddに置換することはできますか?sedでもawkでもいいのです。
2chなのになぜかたらい回しにされてるのですがよろしくお願いします。
0629名無しさん@お腹いっぱい。2007/12/19(水) 22:00:52
#!/bin/sh
ed a.txt << EOS > /dev/null
\$a

.
?bbb?c
ddd
.
\$d
wq
EOS
いったん末尾に1行挿入するのがコツ
06306282007/12/19(水) 22:06:31
1行のコマンドで出来ないものでしょうか?
0631名無しさん@お腹いっぱい。2007/12/19(水) 22:33:42
>>619

かなり、とっつきは悪い。
特にsed編は、使用目的がtroffマクロの置換とか、プリンタ整形言語の整形とか、訳分からん。
awk編はまあ、用例も身近なのが結構有るけど・・・

でも、内容は極めて濃い。
金を出して購入し、何度も読み返す価値は有ると思う。
0632名無しさん@お腹いっぱい。2007/12/19(水) 22:37:34
>>622

いっている意味が良く分からんが、
エスパーすると、それはawkよりsedの方が得意だと思う。
0633名無しさん@お腹いっぱい。2007/12/19(水) 22:44:44
awk '/bbb/{bbb=i};{l[i++]=$0};END{l[bbb]="ddd";for(j=0;j<i;j++){print l[j]}}'
06346282007/12/19(水) 22:52:17
>>633
ありがとう御座います!
あなた様をずっと待ってました・・・!
06356282007/12/19(水) 22:57:16
>>633
それをa.txtに保存するにはどうしたらいいでしょうか?
awkは呪文のようでまったくわかりません。。。
0636名無しさん@お腹いっぱい。2007/12/19(水) 22:59:58
>>634
おいおい、>>633 じゃ大間違いだと思うがww
0637名無しさん@お腹いっぱい。2007/12/19(水) 23:05:57
>>633 は、一番最後に現れた bbb の行を無条件に ddd に置換しているだけ。

そうじゃなくて、>>628 のやりたいのは、
「ccc<改行>bbb」を「ccc<改行>ddd」に置換したいということだろ?
複数行に渡る置換をしたいということ。

sedスレの方に、すでに解答が出てるよ。1行コマンドで行ける。
0638名無しさん@お腹いっぱい。2007/12/19(水) 23:09:21
% cat /tmp/a.txt
aaa
bbb
ccc
bbb

aaa
bbb
ccc
ccc
bbb

aaa
bbb
ccc
bbb
% cat /tmp/a.txt | perl -e '($_ = join("", <>)) =~ s/(aaa\nbbb\nccc\n)bbb/$1ddd/g; print '
aaa
bbb
ccc
ddd

aaa
bbb
ccc
ccc
bbb

aaa
bbb
ccc
ddd
06396282007/12/19(水) 23:13:40
>>637
そうでしたか。
答えはsedスレの何番目ですか?
0640名無しさん@お腹いっぱい。2007/12/19(水) 23:31:14
そうでしたか。ってwww
お前さんは自分が直面している問題を自分で把握してないのか?wwww

sedではないが別解がひとつ上にある。"aaa改行bbb改行ccc改行bbb"を
全て"〜ddd"に痴漢する
0641名無しさん@お腹いっぱい。2007/12/21(金) 02:21:54
>>617
ふつーに見かけるぞ? >awk256倍
しかしこの本が初心者向けかどうかはちと首をひねるがな。
0642名無しさん@お腹いっぱい。2007/12/21(金) 14:28:09
すみません質問です。
ファイルにひとつフィールド列(固定文字)を足したいんですが、
while read do でループより簡潔に書きたいんです。
paste file1 file2 のfile1には固有文字を入れている感じです
お願いします
0643名無しさん@お腹いっぱい。2007/12/21(金) 14:37:23
642です。
awkっての使えばいいことに気がつきましたすみません
0644名無しさん@お腹いっぱい。2007/12/22(土) 00:04:45
「っての」と言う語感が無縁な事象に対してと思えるのに、
「気がつく」のだから、相当な洞察力だな。
0645名無しさん@お腹いっぱい。2007/12/22(土) 00:20:23
このスレ(というか板)、ひょっとして精神年齢が相当ひくい?
学校の宿題とか新人研修の課題を聞きに来る子供ばっかり?
0646名無しさん@お腹いっぱい。2007/12/22(土) 01:56:01
>>645
つ 鏡
0647shell2007/12/22(土) 12:45:37
shell初心者です。

変数 TODAY=20071212(任意指定)として1970-01-01 00:00:00基準からの
経過時刻を秒数で表示したいのですが、方法はありませんか?
0648名無しさん@お腹いっぱい。2007/12/22(土) 12:46:41
つ date -d ... +%s
0649shell2007/12/22(土) 12:48:50
質問2つ目

text.txtに
11 11 11 111 222 333 E
33 44 666 6666 E
と2行記入しているのですが、これを1行ずつ変数に代入できるスクリプトはありますか?
行の空白は半角スペースで最後にEは表示されています。行中の文字は任意の文字列です。
0650shell2007/12/22(土) 12:49:54
dateは本日の日付を求めるshellじゃなかったでしたっけ?
自分で指定した日付で求めたいです。
0651名無しさん@お腹いっぱい。2007/12/22(土) 12:59:52
つ man date -> "-d dateexpr" # MS-DOSかよ!>本日の日付
0652名無しさん@お腹いっぱい。2007/12/22(土) 13:08:24
>>650
「dateは本日の日付を求める…」違います。

せっかく >>648 で正解を教えてもらっているのに、礼も言わずに
そういうことを言う人には質問する権利はありません。

はい、次の方どうぞ

0653名無しさん@お腹いっぱい。2007/12/22(土) 13:10:36
$ cat /tmp/test.txt | while read str; do
> echo "[$str]"
> done
[11 11 11 111 222 333 E]
[33 44 666 6666 E]
$
0654名無しさん@お腹いっぱい。2007/12/22(土) 13:12:04
>>649
つ read hoge; read fuga
0655shell2007/12/22(土) 22:55:46
今スレ開きました。
試してみます。

ありがとうございます。

「dateは本日の日付を求める…」違うですか...
調べます。
0656名無しさん@お腹いっぱい。2007/12/22(土) 23:09:02
「開きました」キター
何でもウィンドウの隠喩w
0657名無しさん@お腹いっぱい。2007/12/22(土) 23:15:08
>>656
DOS時代(ニフ)の頃からある表現なので、
ファイルオープンからきた「開く」だと思ってたけど?違うの?
0658名無しさん@お腹いっぱい。2007/12/23(日) 02:42:27
>>657
いちいち相手しないほうがいいっすよ。
貶すことしかできないやつってどこにでもいますから。
まあこういうやつに限って現実では貶されまくってるわけですけどね。
0659名無しさん@お腹いっぱい。2007/12/23(日) 18:22:15
/home/hoge/fuga/
/home/hoge/fuga/.data
が本来セットであるはずなんですが、
設定ミスで、一部ユーザには
/home/hoge/fuga/
はあっても
/home/hoge/fuga/.data
がありません。

.dataが存在しないフォルダを簡単に調べる方法はないでしょうか。
0660名無しさん@お腹いっぱい。2007/12/23(日) 19:03:27
>>659
for dir in /home/*/fuga
do
[ -f $dir/.data ] || echo $dir
done
0661名無しさん@お腹いっぱい。2007/12/24(月) 08:08:48
文字列に対して、$oldから$newの置換をしたい場合、
echo $line|sed -e s/$old/$new/ だと、
$oldや$newが'/'を含んだ時にエラーになってしまうから、
bashの${line/$old/$new}を使ってしまうのだけど、
他にポータブルないい方法ないでしょうか。
0662名無しさん@お腹いっぱい。2007/12/24(月) 08:33:45
変数がどの文字を含むか予め予期できないとなると、
「,」に逃げるとかはできないしな
0663名無しさん@お腹いっぱい。2007/12/24(月) 10:22:22
コマンドインジェクション可能だから未検証の文字列をコマンドとしてsedに与えてはいけない。
0664名無しさん@お腹いっぱい。2007/12/24(月) 12:30:10
うーん、そうなのですか。
line, old, newがそれぞれ実在のパス(フルパス、相対パス、パスの一部のいずれか)
だと保証できる場合はどうでしょうか。
そもそもsedだと置換え前の文字を正規表現と扱ってしまうから、
期待しないマッチングが発生する可能性もあるけれども。。。
適当なスクリプトに、3つの引数を与えて
その中で処理させたほうがいいのかなぁ。
0665名無しさん@お腹いっぱい。2007/12/24(月) 14:16:55
実在のパスでも、Ctrl-A (0x00) 以外のすべての文字が
パスとして使用可能だからなぁ、、
0666名無しさん@お腹いっぱい。2007/12/24(月) 14:50:27
>665
これ本当ですか?
Ctrl-Aと/以外はファイルやディレクトリ名に使えるってこと?
横から質問で申し訳ない
0667名無しさん@お腹いっぱい。2007/12/24(月) 14:52:42
CTRL-Aは0x01なので嘘です。
0668名無しさん@お腹いっぱい。2007/12/24(月) 14:59:37
CTRL+SPC
0669名無しさん@お腹いっぱい。2007/12/24(月) 15:20:48
Ctrl+@だな。それ以外は本当。
0670名無しさん@お腹いっぱい。2007/12/25(火) 17:49:34
ファイル名にCtrl+Gを含めたら、lsの度に激しくうるさい件について
0671名無しさん@お腹いっぱい。2007/12/25(火) 18:00:35
?に置き換わってうるさくない件について
0672名無しさん@お腹いっぱい。2007/12/26(水) 00:06:34
普通--show-control-charsって常に有効にするだろ
0673名無しさん@お腹いっぱい。2007/12/26(水) 00:32:28
そんなls手が腐るから普通触らない。
0674名無しさん@お腹いっぱい。2007/12/26(水) 03:49:58
半導体業界はcshスクリプトとかtclスクリプトばっか。
ときどき転職したくなる。
0675名無しさん@お腹いっぱい。2007/12/26(水) 10:48:21
CADとかもtcl使っているの多いね。
プラグインとかだけでなく、サービス起動スクリプトまでtcl使っているのがあるし。
0676名無しさん@お腹いっぱい。2007/12/26(水) 11:38:44
TCLは、もともと集積回路設計ツール内蔵スクリプト言語の
ベースとなる拡張可能なスクリプト言語として開発されたからね。
だから半導体の世界では多い。
独自言語使わないで済むのはTCLのおかげ。

Tkとくっついてから他の世界にも普及した。
0677名無しさん@お腹いっぱい。2007/12/27(木) 11:54:46
すみません、
#!/usr/bin/ksh
PALALLEL(){
mp=$!; sp=$$
echo "ぱられる ${mp} ${sp}"
}

PALALLEL &
PALALLEL &

とやったとき最初のmpが取れないんですがどうするべき?

ご教示おねがいします
0678名無しさん@お腹いっぱい。2007/12/27(木) 11:58:48
>>677
当たり前だろ。
最初のPALALLEL()にとっては、$!は存在しないから。
■ このスレッドは過去ログ倉庫に格納されています