シェルスクリプト総合 その19
■ このスレッドは過去ログ倉庫に格納されています
0001シェルスクリプトライター
2011/12/10(土) 20:06:40.38スクリプトのお勉強・自慢・腕試しなどにどうぞ。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashなので特に注意。
FreeBSDユーザは/bin/shの正体がashなので注意。
v7 shに一番近くて、現役のshは、OpenSolaris由来のheirloom sh。
http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sh/
http://heirloom.sourceforge.net/sh.html
・csh/tcshのシェルスクリプトは推奨されません。
(理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
manや参考リンクを見ましょう。
aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
前スレ
シェルスクリプト総合 その18
http://hibari.2ch.net/test/read.cgi/unix/1308195527/
次スレは >>970 で。
0752名無しさん@お腹いっぱい。
2012/04/05(木) 12:39:50.77awkで、getlineを使わずに普通にできる。
ただし、数字は半角で書いてないと計算できない。
0753名無しさん@お腹いっぱい。
2012/04/05(木) 12:48:51.09あっちスレの削除依頼出してきてよ。
0754名無しさん@お腹いっぱい。
2012/04/05(木) 13:03:00.03すみません、やり方がわからないんで・・・
後で出します;
0755名無しさん@お腹いっぱい。
2012/04/05(木) 13:06:43.25getline を使わずにですか・・・
ちょっとヒントいただけますか?
0756名無しさん@お腹いっぱい。
2012/04/05(木) 13:21:01.61awk使わずにシェルだけでできるよ。
ただし、スペースは半角に、数字も半角にしてから実行すること。
標準入力から入力。
#!/bin/sh
p_district=
p_branch=
p_name=
n=0
while read district branch name val; do
if [ "$district" = "$p_district" ] &&
[ "$branch" = "$p_branch" ] &&
[ "$name" = "$p_name" ]; then
n=`expr "$n" + "$val"`
else
[ "$p_district" ] && echo "$p_district" "$p_branch" "$p_name" "$n"
p_district=$district
p_branch=$branch
p_name=$name
n=$val
fi
done
echo "$p_district" "$p_branch" "$p_name" "$n"
0757名無しさん@お腹いっぱい。
2012/04/05(木) 13:33:45.35お〜、有難うございます!大変助かります!
半角にして試して見ます。
ちなみに
$0 テキストファイル
といった具合に、テキストファイルを引数にして読み込み処理する、というようなことも出来るでしょうか?
0758名無しさん@お腹いっぱい。
2012/04/05(木) 13:35:37.33引数にしたかったら、
>>756 のしたから2行目の done のところを done < "$1" に修正すれば良い。
あと、入力ファイルはあらかじめソートされてること
0759名無しさん@お腹いっぱい。
2012/04/05(木) 13:42:26.55すごい!
自分もこんなにあっさりスクリプトが書けるようになりたいものです・・・
758 さん、有難うございました、大変勉強になりました。
0760名無しさん@お腹いっぱい。
2012/04/05(木) 13:50:38.480761名無しさん@お腹いっぱい。
2012/04/05(木) 14:44:15.710762名無しさん@お腹いっぱい。
2012/04/07(土) 17:42:25.29特定のディレクトリ以下に アクセス不能とか移動不能なものが
あるかどうかを調べたいんですが、findでいいですかね
0763名無しさん@お腹いっぱい。
2012/04/07(土) 19:40:38.64グループでOKになってるときのパターンがネックだ
これのせいでワンライナーにならん
0764名無しさん@お腹いっぱい。
2012/04/07(土) 22:52:59.06find . ! -readable | wc -l
でダメ?
0765sage
2012/04/10(火) 19:58:25.17とかやると,
[1] + suspended (tty output) ...
とかなって処理が終了しない.なぜぇ・・・
0766名無しさん@お腹いっぱい。
2012/04/10(火) 21:04:40.050767名無しさん@お腹いっぱい。
2012/04/11(水) 08:00:04.70面白いと思う
0768名無しさん@お腹いっぱい。
2012/04/12(木) 09:02:11.67はずして実行したら {1..10}.txt とかできたぞ
どうしてくれる
マジレスすると、commandの中身なによ
0769sage
2012/04/12(木) 10:33:02.930770名無しさん@お腹いっぱい。
2012/04/12(木) 19:19:17.010771名無しさん@お腹いっぱい。
2012/04/12(木) 19:30:36.07回答欲しかったらもっと具体的に "how to repeat" 書いてくれ
0772名無しさん@お腹いっぱい。
2012/04/12(木) 21:09:49.38そのcommandのプログラムがSIGTTOUをSIG_DFLに戻してしまってるんだろ。
普通ならシェル側でSIGTTOUはSIG_IGNにするからsuspendはしないようになってる。
0773名無しさん@お腹いっぱい。
2012/04/12(木) 21:25:50.42Steps to Reproduce だろ
0774名無しさん@お腹いっぱい。
2012/04/12(木) 21:34:14.02How to repeatで合ってる。というか、そんなところに突っ込んでも面白くない。
0775名無しさん@お腹いっぱい。
2012/04/12(木) 22:19:43.600776名無しさん@お腹いっぱい。
2012/04/12(木) 22:24:50.960777名無しさん@お腹いっぱい。
2012/04/12(木) 22:27:19.83「バグの再現手順」だろ? と突っ込んでるようなモン。
0778名無しさん@お腹いっぱい。
2012/04/12(木) 23:01:56.84http://www.gnu.org/software/gnats/doc/3_113_1/gnats_1.html
0779名無しさん@お腹いっぱい。
2012/04/13(金) 06:11:12.98エスパーするとzshの最近のバージョンでのバグ。
0780名無しさん@お腹いっぱい。
2012/04/13(金) 14:26:30.54で起きる奴とおんなじ.どうすればいいんだろ・・
0781名無しさん@お腹いっぱい。
2012/04/13(金) 14:34:14.580782名無しさん@お腹いっぱい。
2012/04/13(金) 14:44:26.87>>768の件.
0783名無しさん@お腹いっぱい。
2012/04/13(金) 14:44:40.34set +m
で、ジョブコントロールを無効にすれば桶。
ただ、シェルスクリプト中から起動すればデフォで set +m 状態なんだがな。
コマンドラインから直接起動してるのか。
0784名無しさん@お腹いっぱい。
2012/04/14(土) 21:01:39.51shell script書いててはまったんだけど、
ls -l /etc | sort -k4 -n
がファイルサイズでソートしてくんない。
こんな↓感じで、なんか部分的にしかソートしてくれないみたい。
http://dpaste.org/ri4On/
バグ?
理由を知ってる人がいたら教えてちょうだい。
環境: debian squeeze
$ uname -a
Linux bauhaus 3.2.0-2-rt-686-pae #1 SMP PREEMPT RT Fri Apr 13 02:23:30 JST 2012 i686 GNU/Linux
$ sort --version
sort (GNU coreutils) 8.5
0785名無しさん@お腹いっぱい。
2012/04/14(土) 21:09:58.78sort -k5 -n だろ
0786名無しさん@お腹いっぱい。
2012/04/14(土) 21:10:24.240787名無しさん@お腹いっぱい。
2012/04/14(土) 21:15:57.76> 理由を知ってる人がいたら教えてちょうだい。
使い方が間違っている。
0788名無しさん@お腹いっぱい。
2012/04/14(土) 21:18:22.790789名無しさん@お腹いっぱい。
2012/04/14(土) 21:26:12.51-k POS1[,POS2]
-K POS1[,POS2] ソートフィールド指定の POSIX 形式。今後はこちらが
推奨される。行の POS1 から POS2 までのフィールドを指定する。
POS2 を含む。 POS2 が省略されたら行末まで。 フィールドと文字位置
はそれぞれ 0 から数えはじめる。
て書いてあったんだもん。
それを何も考えず信じたのでした。
LANG=C man sort だと、
-k, --key=POS1[,POS2]
start a key at POS1 (origin 1), end it at POS2 (default end of line)
てなってるのね。
確かに -k5ならソートしてくれたよ。
なんだかスレ汚し失礼しました。
0790名無しさん@お腹いっぱい。
2012/04/14(土) 21:34:49.420791名無しさん@お腹いっぱい。
2012/04/15(日) 01:03:11.15さすが Linux とおもた。
0792名無しさん@お腹いっぱい。
2012/04/15(日) 01:13:16.430793名無しさん@お腹いっぱい。
2012/04/15(日) 01:18:04.06しとくのオススメ
0794名無しさん@お腹いっぱい。
2012/04/15(日) 01:20:40.590795名無しさん@お腹いっぱい。
2012/04/15(日) 02:33:57.03翻訳されたのが嬉しかった。
GNU bash 4.2 の翻訳
http://linuxjm.sourceforge.jp/INDEX/gnu.html#GNU_bash
0796名無しさん@お腹いっぱい。
2012/04/15(日) 11:22:51.82function foo {
foo
}
しかし当然ながら無限ループになります。
解決策としては
function foo {
`which foo`
}
という方法があります。
しかし毎回 which コマンドを起動するのがちょっと気にかかります。
別の方法として
function foo {
¥foo
}
というのを試しましたが、だめでした。¥foo はエイリアスには効くけど関数にはききませんでした。
というわけで、今のところ which コマンドを使う方法しかなさそうですが、もっといい方法があれば教えて下さい。
0797名無しさん@お腹いっぱい。
2012/04/15(日) 11:26:42.70function foo {
command foo
}
そのための「command」コマンド。
0798名無しさん@お腹いっぱい。
2012/04/15(日) 12:24:24.87bash$ help function
とか
bash$ help command
とかするとその部分の説明文だけ表示してくれる
0799名無しさん@お腹いっぱい。
2012/04/15(日) 13:24:53.76/usr/bin/foo
とかすればいいんじゃないの?
0800名無しさん@お腹いっぱい。
2012/04/15(日) 13:34:57.91最適解(>>797)が既に出てるのに、外した回答するオマエは黙ってろ。
PATHが違ったら適応できないだろw
0801名無しさん@お腹いっぱい。
2012/04/15(日) 16:01:28.21〜の方が良いと書いてあれば別だが。
0802名無しさん@お腹いっぱい。
2012/04/15(日) 16:16:51.47>>796 の質問で、わざわざ `which foo` と書いてることから、
絶対PATHで書いたのでは問題の解決にならないことは読みとれる。
質問者自信も絶対PATHを使う方法は知っている(けどそれじゃ駄目)と読みとれる。
質問の回答になってないのだから問題視されてもしょうがない。
0803名無しさん@お腹いっぱい。
2012/04/16(月) 01:51:19.72>>799みたいなトンチンカンな回答にも丁寧に答えてあげている
>>800の優しさに気づけ
0804名無しさん@お腹いっぱい。
2012/04/17(火) 15:40:51.44「command」なんて初めて知りました。完璧です。ありがとうございました。
>>802
状況としてはまったくそのとおりで、すばらしいエスパーっぷりですが、
799はそこまで敵視されるようなことを書いてるわけじゃないので、
そんなに怖がらせなくてもいいかなと思いました。
技術者同士はみんな仲良くね!戦うべき相手は別にいるよ!
0805名無しさん@お腹いっぱい。
2012/04/17(火) 16:49:46.48彼なりにイカしたレスだとお考えになっているのでしょう。
しばらくここにいれば慣れます。
0806名無しさん
2012/04/23(月) 01:47:23.080807名無しさん@お腹いっぱい。
2012/04/28(土) 14:15:07.91環境変数ならぬ環境関数みたいな
便利だと思うんだけど
0808名無しさん@お腹いっぱい。
2012/04/28(土) 14:19:23.03え? できるけど。
export -f
0809名無しさん@お腹いっぱい。
2012/04/29(日) 08:45:26.54bash乙
0810名無しさん@お腹いっぱい。
2012/04/29(日) 09:44:51.95/ \
/ _ノ ヽ、_ \
/ o゚⌒ ⌒゚o \ 不毛な言い争いがまた始まるお…
| (__人__) |
\ ` ⌒´ /
0811名無しさん@お腹いっぱい。
2012/04/29(日) 10:46:16.860812名無しさん@お腹いっぱい。
2012/04/29(日) 17:13:31.08ほんとだ、bashだとexport -fでできるのね
zshだと駄目なんだけどオプションが違うんだろうか
0813名無しさん@お腹いっぱい。
2012/04/29(日) 17:16:47.950814名無しさん@お腹いっぱい。
2012/04/29(日) 18:14:30.17そうなんだぁ・・・
いっそbashに戻ろうかな
0815名無しさん@お腹いっぱい。
2012/05/06(日) 03:50:24.36質問です。
複数のコマンドの実行結果をソートしたいですが、うまくいきません。例えば、
イメージ的には以下のような感じ。
{
cat FILE_A
find PATH1 -print
find PATH2 -print
find PATH3 -print
} | sort > FILE_A
以下を試しました
find PATH1 -print >> FILE_A
find PATH2 -print >> FILE_A
find PATH3 -print >> FILE_A
cat FILE_A | sort > FILE_A
こうすると最後の FILE_A のファイルに結果がすべて出力されず尻切れになり
ます。
0816名無しさん@お腹いっぱい。
2012/05/06(日) 03:59:02.05$ cat <(find PATH1) <(find PATH2) <(find PATH3) | sort
$ cat < FILE_A | sort > FILE_A
が失敗するのはまあそんなものだと思っておけばいい。
同じファイルから読み込んで出力するのは失敗する。
$ cat < FILE_A | sort > FILE_B
ならおk
0817名無しさん@お腹いっぱい。
2012/05/06(日) 04:09:18.13みたいな手もあるが、間違えたら泣ける。
0818名無しさん@お腹いっぱい。
2012/05/06(日) 04:15:04.88find PATH1 PATH2 PATH3 | sort
でいいよな。
0819名無しさん@お腹いっぱい。
2012/05/06(日) 05:15:17.42> cat FILE_A | sort > FILE_A
マルチタスクな OS では普通パイプやリダイレクトの際に前後の
プロセスが同時に起動する。
ファイルを読むプロセスが終了するのを待ってファイルを書くプ
ロセスが起動する訳ではない。
なので、上記の場合は最後に書き込むファイル名を変更しなければならない。
0820名無しさん@お腹いっぱい。
2012/05/06(日) 14:36:51.94cat FILE_A > "$TEMP"
find PATH1 -print >> "$TEMP"
find PATH2 -print >> "$TEMP"
find PATH3 -print >> "$TEMP"
sort "$TEMP" > FILE_A
0821名無しさん@お腹いっぱい。
2012/05/06(日) 14:53:36.250822名無しさん@お腹いっぱい。
2012/05/06(日) 15:27:35.80http://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html#sort-invocation
cat FILE_A | sort -o FILE_A
0823名無しさん@お腹いっぱい。
2012/05/06(日) 16:20:24.14catとパイプが無駄です。
sort -o FILE_A FILE_A
0824名無しさん@お腹いっぱい。
2012/05/06(日) 17:20:10.080825名無しさん@お腹いっぱい。
2012/05/06(日) 18:55:31.700826名無しさん@お腹いっぱい。
2012/05/06(日) 19:22:02.880827名無しさん@お腹いっぱい。
2012/05/06(日) 19:23:49.290828名無しさん@お腹いっぱい。
2012/05/07(月) 19:19:08.780829名無しさん@お腹いっぱい。
2012/05/07(月) 21:03:44.73対話的コマンドでもexpectでなんとかなる
0830名無しさん@お腹いっぱい。
2012/05/07(月) 21:11:42.22そういう意味じゃなくて、シェルスクリプト中で su -c hoge とかしないで
root権限の動作をさせたいという質問かとエスパー。
0831名無しさん@お腹いっぱい。
2012/05/07(月) 21:16:30.15昔あったsuidperlみたいなののbash版を探してみたけどないみたいだし。
sudersに対象となるスクリプトに対してNOPASSWDを設定するぐらいしか思いつかないや。
0832名無しさん@お腹いっぱい。
2012/05/08(火) 02:00:49.38できます
コマンドラインを実行するだけのプログラムを作って
setuidするば
0833名無しさん@お腹いっぱい。
2012/05/08(火) 07:52:21.31>>831
0834名無しさん@お腹いっぱい。
2012/05/09(水) 13:22:49.97ここに書いてあるシェルスクリプトを動かしてみたんですが、
Syntax error: "do" unexpectedと返されてしまいます
ヒントだけでもいいんで教えてください。
0835名無しさん@お腹いっぱい。
2012/05/09(水) 13:28:11.27bash -x secrets.sh
0836名無しさん@お腹いっぱい。
2012/05/09(水) 13:29:47.52わからないなら黙ってろ
0837835
2012/05/09(水) 13:30:45.770838名無しさん@お腹いっぱい。
2012/05/09(水) 15:17:41.550839名無しさん@お腹いっぱい。
2012/05/10(木) 06:54:48.810840名無しさん@お腹いっぱい。
2012/05/14(月) 22:36:21.02function chdir {
if [ -r "$1" -a -d "$1" -o "$1" = "" ] ; then
local i
for i in 8 7 6 5 4 3 2 1 0 ; do
dirstack[$i+1]=${dirstack[$i]}
done
dirstack[0]=`pwd`
\cd $1
fi
pwd
}
function ds {
echo "p:"`pwd`
local i
for i in 0 1 2 3 4 5 6 7 8 9 ; do
echo "$i:${dirstack[$i]}"
done
}
bash用のをcsh(tcshですが)に書き換えてもらえないでしょうか。
0841名無しさん@お腹いっぱい。
2012/05/14(月) 22:36:59.98dirstack[10]=`pwd`
\cd ${dirstack[0]}
local i
for i in 0 1 2 3 4 5 6 7 8 9 ; do
dirstack[$i]=${dirstack[$i+1]}
done
pwd
}
function nd {
dirstack[10]=`pwd`
\cd ${dirstack[9]}
local i
for i in 8 7 6 5 4 3 2 1 0 ; do
dirstack[$i+1]=${dirstack[$i]}
done
dirstack[0]=${dirstack[10]}
pwd
}
0842名無しさん@お腹いっぱい。
2012/05/15(火) 09:15:03.980843名無しさん@お腹いっぱい。
2012/05/15(火) 16:36:43.46体に馴染んでるんで…すいません
0844名無しさん@お腹いっぱい。
2012/05/16(水) 16:34:35.79デフォルトのBourne Shellではチルダ展開がないようなので、posix shellにて
チルダ展開が必要な場合がある、ファイル名に空白等を含んだものが、パラメータに入っているとして、
file_name="~/src/te st"
echo "${file_name}をチルダ展開しlsします。\n"
ls -l "$( eval echo -n ${file_name} )"
0845名無しさん@お腹いっぱい。
2012/05/16(水) 16:40:45.810846名無しさん@お腹いっぱい。
2012/05/16(水) 17:10:41.70例が悪い。その1番下の行の
ls -l "$( eval echo -n ${file_name} )"
だって、複数の空白が空白1個にまとめられちゃうし、
$ < > 等の記号が含まれると ${file_name} (クォートなし)の展開と
evalの展開で大変なことになるぞ。
0847名無しさん@お腹いっぱい。
2012/05/16(水) 17:30:39.54でも考えても、これくらいしか思いつかなかったので、
いい加減にして、聞いた方が早いかと書き込んだんだよ。
0848名無しさん@お腹いっぱい。
2012/05/16(水) 17:34:06.75その他の空白とか * $ < > とかの解釈はさせないって方法がないんだよな。
sedでチルダを $HOME に書き換えろ。
0849名無しさん@お腹いっぱい。
2012/05/16(水) 17:46:31.95file_name="~/src/te st * $ < >"
ls -l "${file_name/\~/$HOME}"
0850名無しさん@お腹いっぱい。
2012/05/16(水) 18:49:13.65ls -l "$( echo -n "${file_name}" | sed s#^~#$HOME# )"
0851844
2012/05/16(水) 21:00:34.05ls -l "$( [ "${file_name%%/*}" = "~" ] && echo "$HOME/${file_name#~/}" || echo "${file_name}" )"
if [ "${file_name%%/*}" = "~" ]
then ls -l "$HOME/${file_name#~/}"
else ls -l "${file_name}"
fi
■ このスレッドは過去ログ倉庫に格納されています