トップページunix
1002コメント330KB

シェルスクリプト総合 その25©5ch.net

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。 転載ダメ©2ch.net2015/08/14(金) 23:42:01.51
シェルスクリプトの総合スレです。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
 bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
 Linuxユーザは/bin/shの正体がbashまたはdashなので特に注意。
 FreeBSDユーザは/bin/shの正体がashなので注意。
 v7 shに一番近くて、現役のshは、OpenSolaris由来のheirloom sh。
  http://src.illumos.org/source/xref/illumos-gate/usr/src/cmd/sh/
  http://heirloom.sourceforge.net/sh.html
・csh/tcshのシェルスクリプトは推奨されません。
 (理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
 manや参考リンクを見ましょう。
 aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルで使えるワイルドカード等は正規表現ではありません。
 正規表現の話題はスレ違い(正規表現スレへ)
・シェルスクリプトのことをシェルってゆーな
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
 awkまたはperlの方が適した処理にはそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
□回答者への注意事項:
・シェルスクリプトでの処理方法を質問しているのに、よくわからずに
 「そういうのはperl使いましょう」と回答するのはやめましょう。
 安易にperlに逃げずにシェルスクリプトで処理するのが頭のいいやり方。
前スレ
シェルスクリプト総合 その24
http://peace.2ch.net/test/read.cgi/unix/1415634843/
0002名無しさん@お腹いっぱい。2015/08/14(金) 23:42:43.85
シェルスクリプトの総合スレです。
初心者、学生、アマチュア、プロ、シェルの種類や OS を問いません。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずはテンプレートをご覧下さい。

□A. お約束
1. 特記なき場合は #!/bin/sh がデフォルトです。この場合可搬性に注意し、
 Traditional Bourne Shell もしくは、POSIX 相当のスクリプトでお願いします。
 bash / zsh / ksh / ash / dash や OS 等に依存する場合は、明示しましょう。
 良く分からない方は、使用している OS を書いておけば OK です。是非ご参加下さい。
2. 質問する前に、まず自分で調べましょう。ただし、
 「聞くは一時の恥、聞かぬは一生の恥」です。積極的に参加しましょう。
3. 相手を侮辱する発言、失礼な発言は差し控え、知的な議論を楽しみましょう。
4. 他者には様々な環境や事情、目的が有る事に留意し、無下に扱う様な発言は
 控えましょう。

□B. お約束の補足
1. Mac OS X では、/bin/sh の実体は bash です。また、一般的に BSD 系 や
 GNU/Linux の方は、/bin/sh がシンボリックリンクですので、注意して下さい。
 ls -l /bin/sh や readlink -e /bin/sh で確かめて下さい。
2. 可搬性については、下記 F.1 を参照して下さい。
3. POSIX については、man 7 standards や下記 F.2 ( の特に Shell & Utilities )
 を参照して下さい。
4. Traditional Bourne Shell とは、UNIX Version 7 から SVR4.2 の /bin/sh を元に
 小さなの改変を加え主に商用 UNIX で残されているものです。( 下記 F.3 参照 )
5. Traditional Bourne Shell で入手しやすい sh は、後期 SVR4.0 から派生し、
 SunOS 5 / OpenSolaris を経た、Heirloom Bourne Shell です。
 SVR4 / SVID3 相当です。同様の Unix utilities も扱っています。
 ( 下記 F.3 参照 )
0003名無しさん@お腹いっぱい。2015/08/14(金) 23:44:39.30
□C. 初心者へのアドバイス
1. シェルスクリプトのことをシェルってゆーな
2. 知らないコマンドが出てきたら man コマンドで調べましょう。
3. UNIX には、シェルスクリプトに便利な小さなコマンドが色々あります。
 apropos ないしは man -k でそれらしい単語による簡単な検索もできます。
4. シェルの構文や内部コマンドは man sh で。英語は LANG=C man shで。
5. 思い通りに動かないときは、まずは #!/bin/sh -x でトレースしましょう。
6. 適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
 awk / perl / javascript / ruby / python 等、他の (スクリプト) 言語の方が
 適した処理にはそちらを使いましょう。
7. シェルで使えるワイルドカード等は正規表現ではありません。
 正規表現の話題は正規表現スレへ
8. csh / tcsh のシェルスクリプトは推奨されません。理由は下記を参照
 http://www.speech-lab.org/~hiroki/csh-whynot.euc
9. cat file|すんなハゲ
 a. 詳細は "Useless Use of Cat" UUOC で検索して下さい
 b. 有用な場合も有ります Useful use of cat(1) 英文
  http://www.in-ulm.de/~mascheck/various/uuoc/

□D. シェルスクリプトでよく使うコマンド
1. 制御・条件判定系: [, test, expr, true, false, yes, getopts
2. テキスト処理系: cat, awk, sed, tr, sort, uniq, grep, wc, head, tail, cut,
 paste, comm, join
3. ファイル検索系: find ( スペースなどを含むファイル名を正しく処理するため、
 find は -exec command {} + を推奨。
 他に -print0、xargs は -0 オプションという方法もあるが Solaris 非対応 )
4. ディレクトリ系: basename, dirname
5. 出力系: echo, printf
6. 対話コマンド制御系: expect
7. http / ftp の処理自動化: wget, curl
0004名無しさん@お腹いっぱい。2015/08/14(金) 23:50:19.57
□E. 学習用テキスト
1. Bourne Shell自習テキスト ( 1993年 ) pdf お薦め
 http://lagendra.s.kanazawa-u.ac.jp/ogurisu/manuals/sh-text/sh/
 (↑サイト消滅かも)
 http://ayapin.film.s.dendai.ac.jp/~matuda/Lecture/PDF/sh-two.pdf
2. UNIX FAQ LIST
 http://www.nurs.or.jp/~asada/FAQ/UNIX/UNIX.FAQ.html
(3. シェルを使おう - 導入からプログラミングまで - ( 2002年 )
 http://www.netfort.gr.jp/~tomokuni/lms/shell/ (リンク切れ))

□F. 参考リンク
1. 可搬性関連
 a. autoconf マニュアル 移植性のあるシェルプログラム
  http://www.gnu.org/software/autoconf/manual/autoconf.html#Portable-Shell
  http://www.geocities.jp/fut_nis/html/autoconf-ja/Portable-Shell.html
 b. Portability talk [Bash Hackers Wiki] 英文
  Obsolete and deprecated syntax も見る価値有り
  http://wiki.bash-hackers.org/scripting/nonportable
 c. How to make bash scripts work in dash 英文
  http://mywiki.wooledge.org/Bashism
 d. DashAsBinSh 英文
  https://wiki.ubuntu.com/DashAsBinSh
 e. Portable Shell Programming 英文
  http://www.in-ulm.de/~mascheck/various/portability/
0005名無しさん@お腹いっぱい。2015/08/14(金) 23:53:33.73
2. POSIX
 The Open Group Base Specifications Issue 7 IEEE Std 1003.1, 2013 Edition 英文
 http://pubs.opengroup.org/onlinepubs/9699919799/
3. Traditional Bourne Shell 関連
 a. The Traditional Bourne Shell Family History and Development 英文
  http://www.in-ulm.de/~mascheck/bourne/
 b. BourneShell / Where does the Bourne shell live? 英文
  http://mywiki.wooledge.org/BourneShell
 c. The Heirloom Bourne Shell 英文
  http://heirloom.sourceforge.net/
4. マニュアル
 a. The Base Specifications Issue 7, 2013 Edition 英文
  http://pubs.opengroup.org/onlinepubs/9699919799/nfindex.html
 b. FreeBSD 日本語マニュアル検索
  http://www.jp.freebsd.org/man-jp/search.html
 c. JM Project (Japanese)
  http://linuxjm.sourceforge.jp/
5. FAQ 等
 a. UNIXの部屋 ( 2011年 )
  http://x68000.q-e-d.net/~68user/unix/
 b. Linux JF (Japanese FAQ) Project
  http://linuxjf.osdn.jp/
 c. Advanced Bash-Scripting Guide 英文
  http://www.tldp.org/LDP/abs/html/
 d. Unix Programming FAQ 日本語訳 ( 2000年 )
  http://www.race.u-tokyo.ac.jp/~moro/unix-programmer/
0006名無しさん@お腹いっぱい。2015/08/14(金) 23:56:30.37
6. ツール
 a. web tool です。Vim syntastic や Emacs の Flycheck でも使えます
  ShellCheck
  http://www.shellcheck.net/about.html
 b. vim 用 syntastic
  https://github.com/scrooloose/syntastic
 c. checkbashisms も使用してチェック duggan/shlint GitHub
  https://github.com/duggan/shlint

□G. 前スレ
1. ☆シェルスクリプトを勉強するにあたって☆
 http://hibari.2ch.net/test/read.cgi/unix/989659936/
2. 便利なシェルスクリプト見せろ
 http://pc.2ch.net/test/read.cgi/unix/996949546/
3. シェルスクリプト総合 その1
 http://pc5.2ch.net/test/read.cgi/unix/1101820646/
後略。検索して下さい
0007名無しさん@お腹いっぱい。2015/08/14(金) 23:57:59.64
□H. 関連スレ(UNIX板/プログラム板)
1. sed
 http://peace.2ch.net/test/read.cgi/unix/1085730992/
2. 正規表現
 http://peace.2ch.net/test/read.cgi/unix/1039165754/
3. Regular Expression(正規表現) Part13
 http://peace.2ch.net/test/read.cgi/tech/1415149975/
4.Perlについての質問箱 64箱目 [転載禁止](c)2ch.net
 http://peace.2ch.net/test/read.cgi/tech/1417291896/
5. ECMAScript デス 4
 http://peace.2ch.net/test/read.cgi/tech/1325448978/
6. Ruby 初心者スレッド Part 57©2ch.net [転載禁止](c)2ch.net
 http://peace.2ch.net/test/read.cgi/tech/1426165733/
7. Pythonのお勉強 Part50
 http://peace.2ch.net/test/read.cgi/tech/1413474092/
8. 【node.js】サーバサイドjavascript 3【io.js】(c)2ch.net
 http://peace.2ch.net/test/read.cgi/tech/1419673207/

□I. 現在評価待ち: X.n は予定した追加先。主にスレ立て人の判断保留用。
0008名無しさん@お腹いっぱい。2015/08/15(土) 00:04:34.32
テンプレは以上です。
漏れや要求があれば各自追記願います。
0009名無しさん@お腹いっぱい。2015/08/15(土) 03:33:33.31
Windows用のはないの?
0010名無しさん@お腹いっぱい。2015/08/15(土) 13:42:11.47
Windows用の何?
0011名無しさん@お腹いっぱい。2015/08/15(土) 14:41:40.48
bashとかTraditional Bourne Shellとか。
0012名無しさん@お腹いっぱい。2015/08/15(土) 17:47:20.99
Cygwin入れれば
0013名無しさん@お腹いっぱい。2015/08/16(日) 00:14:04.65
ping使うやつが移植性無くなるな
0014名無しさん@お腹いっぱい。2015/08/16(日) 21:47:33.05
テキストファイルの分割で教えてください

例えば95行のテキストファイルを10分割するとき、
splitだと10行のファイルが9個と5行のファイルが1個できますが
そういう分割ではなく、10行のファイルを5個、9行のファイルを5個、
というように、等分に近くなるように分割したいです

今はforループで、1行目はファイル1に、2行目はファイル2に、
途中略して10行目はファイル10に、そして11行目はファイル1に、
みたいに仕分けてるのですが、splitの様にファイル先頭からの並び通りに
等分したく思ってます
0015名無しさん@お腹いっぱい。2015/08/16(日) 22:42:11.52
すればいいじゃん。
0016名無しさん@お腹いっぱい。2015/08/16(日) 23:56:46.15
>>14
awk で行番号見ながら出力ファイルを変えれば?
以下は out.0〜9 に出力する例。
動かしてみた感じだと perl で真面目にプログラム書いた方が処理速度的には速そうね。

#!/bin/sh
INFILE="$1"
LINE=$(wc -l < "$INFILE")
SPMOD=$(expr $LINE % 10)
SPDIV=$(expr $LINE / 10)
[ "$SPMOD" != 0 ] && SPDIV=$(expr $SPDIV + 1)
awk "BEGIN{I=0; F=\"out.\"I; DIV=${SPDIV}; B=DIV;}
{print \$0 > F; if(NR == B){I++; if(I==${SPMOD}){DIV--;}
F=\"out.\"I; B+=DIV;}}" "$INFILE"
0017名無しさん@お腹いっぱい。2015/08/17(月) 00:28:08.28
GNU coreutils の split コマンドだと -n オプションってのがある。

$ split -n l/10 95lines.txt

# 1/10 じゃなくて l/10 ね(line の l)

ただ、こうなる↓

$ wc -l xa?
12 xaa
9 xab
9 xac
9 xad
9 xae
9 xaf
9 xag
9 xah
9 xai
11 xaj
95 合計
0018名無しさん@お腹いっぱい。2015/08/17(月) 07:22:58.29
>>16
なるほど
まずは処理内容を勉強して、考えます

>>17
なんか微妙な分け方ですね…
GNU版の採用や、96とか97とかになったらどうなるかとか、調べてみます
0019名無しさん@お腹いっぱい。2015/08/23(日) 21:52:42.48
ubuntuです。超初歩の段階なのですが
for file in ${1}/*
do
echo "${file}"
done
上記のコードで
$sh test.sh ~/Desktop/foo
とすると期待通りに
/home/hoge/Desktop/foo/a
/home/hoge/Desktop/foo/b
/home/hoge/Desktop/foo/c
と表示されるのですが
$sh test.sh "~/Desktop/foo"
とダブルクォートでくくると
~/Desktop/foo/*
と表示されてしまいます
でも空白の入ったパスを渡したいときはダブルクォートでくくらないといけませんよね?どうすればいいですか
${1}/*を"${1}/*"としても"${1}"/*としてもうまくいきませんでした
0020名無しさん@お腹いっぱい。2015/08/23(日) 22:25:01.69
>>19
チルダがクォートされているかどうかで違う
$ echo ~/Desktop/foo
/home/hoge/Desktop/foo
$ echo "~/Desktop/foo"
~/Desktop/foo
0021名無しさん@お腹いっぱい。2015/08/23(日) 22:53:07.70
>>19
$ sh test.sh "${HOME}/Desktop/foo"
0022192015/08/23(日) 23:32:18.17
>>20-21
レスどうもありがとうございます
コード側の問題じゃなくて渡す側の書き方に問題があったんですね
空白を含んでいないパスは期待どおりになりました
が空白を含んでいる場合はやっぱり「*」が展開されずに
$ sh test.sh "/home/hoge/Desktop/foo bar"
または
$ sh test.sh "${HOME}/Desktop/foo bar"
とすると
/home/hoge/Desktop/foo
bar/*
と表示されてしまいます
0023192015/08/23(日) 23:37:21.98
すみません
${1}/* と "${1}/*" はだめでしたが "${1}"/* としたらうまくいきました
ダブルクォートって難しいです
0024名無しさん@お腹いっぱい。2015/08/24(月) 04:09:11.65
${1}/ 中のファイルに空白を含むファイル名があるとダメ

/home/hoge/Desktop/foo bar/space ship.txt があると

/home/hoge/Desktop/foo bar/space
ship.txt

と2行に渡って表示される
0025名無しさん@お腹いっぱい。2015/08/25(火) 09:55:00.50
そうでもないよ
$ cat test.sh
#!/bin/sh
for f in "$1"/*
do
echo "$f"
done

$ touch "space ship.txt"
$ sh test.sh .
./space ship.txt
./test.sh
0026名無しさん@お腹いっぱい。2015/08/25(火) 11:38:42.71
>>24>>25 と同様そうでもない
対象ディレクトリと対象ディレクトリ内のファイル名の両方にスペースが含まれて
いても問題ない
あと、ソースに渡された引数+"/*"がどう展開されるかの表示を追加

bash-2.05$ cat test.sh
#!/bin/sh

echo -n "arg/* = '"
echo -n "${1}"/*
echo "'"
echo

for file in "${1}"/*
do
echo "${file}"
done

exit 0
0027262015/08/25(火) 11:40:11.64
bash-2.05$ mkdir "foo bar"
bash-2.05$ cd "foo bar"
bash-2.05$ touch "space ship.txt"
bash-2.05$ touch space_ship.txt
bash-2.05$ cd ..
bash-2.05$ tree
`-+ .
+-- foo bar
| +-- space ship.txt
| +-- space_ship.txt
+-- test.sh

1 directory 3 files
bash-2.05$ sh test.sh "foo bar"
arg/* = 'foo bar/space ship.txt foo bar/space_ship.txt'

foo bar/space ship.txt
foo bar/space_ship.txt
bash-2.05$
0028名無しさん@お腹いっぱい。2015/08/25(火) 12:23:17.60
>>25
>>24 が駄目と言ってるのは ${1} の場合の話だろw

"$1"ならもちろん問題ないよ。
0029名無しさん@お腹いっぱい。2015/08/25(火) 12:29:22.17
bash-2.05 とか古いの使うにも程がある。劣度法度9か何かか?
0030名無しさん@お腹いっぱい。2015/08/25(火) 12:55:51.30
>>28
いや…ファイルの話だよね?割りとどうでもいい流れだけど一応
$ cat test.sh
#!/bin/sh
for f in ${1}/*
do
echo "$f"
done

$ ls
space ship.txt test.sh
$ sh test.sh .
./space ship.txt
./test.sh
$
0031名無しさん@お腹いっぱい。2015/08/25(火) 13:12:03.64
話を理解していない人々が多過ぎる。スルーしよw
0032名無しさん@お腹いっぱい。2015/08/25(火) 13:14:16.88
>>30
その場合、 ${1} に . が代入されるから問題が起きてないだけ。
${1} とか半端な記述せずに "$1"にすること。${1}ってクォートなしの $1 と同じだから。
0033262015/08/25(火) 13:25:30.87
「"${1}"」ではなくて「${1}」という記述にこだわるならファイル名にスペースが
含まれる場合の常套手段で「IFS」を「改行コード」のみに設定すればOK

bash-2.05$ cat test.sh
#!/bin/sh

IFS_BACKUP=$IFS
IFS="
"

echo -n "arg/* = '"
echo -n "${1}"/*
echo "'"
echo

for file in ${1}/*
do
echo "${file}"
done

IFS=$IFS_BACKUP

exit 0
0034332015/08/25(火) 13:26:35.02
【続き】
bash-2.05$ tree
`-+ .
+-- foo bar
| +-- space ship.txt
| +-- space_ship.txt
+-- test.sh

1 directory 3 files
bash-2.05$ sh test.sh "foo bar"
arg/* = 'foo bar/space ship.txt foo bar/space_ship.txt'

foo bar/space ship.txt
foo bar/space_ship.txt
bash-2.05$
0035名無しさん@お腹いっぱい。2015/08/25(火) 13:30:12.68
>>26 それは改行コード入りファイル名があるからNG
0036名無しさん@お腹いっぱい。2015/08/25(火) 13:58:06.49
このスレの住人にとっては当たり前過ぎる基本的初歩的なことをわざわざ多くの行数使って書き込まれてもなぁ
0037名無しさん@お腹いっぱい。2015/08/30(日) 12:52:52.88
>>13
最近cygwin使ってないんで試してないけど
神が現れてsudo実装してping打てるようになった模様
詳細はcygwinスレ参照

そうそうcygwinのpingって何か違ったんだっけ?
0038名無しさん@お腹いっぱい。2015/09/06(日) 16:40:59.13
引数 $1 が function の中から参照できない
標準では全部グローバルのスコープじゃなかったのか?

グローバル変数に引数をコピーするとグローバル変数は参照できるけど
引数はそういうものなのか?

~/ cat bug.sh
function bug_version {
echo "argument $1 can't handle in function"
}
bug_version
echo "argument $1 can handle out of function"

~/ sh bug.sh arg
argument can't handle in function
argument arg can handle out of function
0039名無しさん@お腹いっぱい。2015/09/06(日) 17:58:01.08
>>38
> 引数 $1 が function の中から参照できない
> 標準では全部グローバルのスコープじゃなかったのか?
【ポイント】
 シェル関数内の位置パラメータと特殊パラメータ「$#」はシェル関数内のみで有効
【説明】
 シェル関数の実行には『引数』を付けることができ、シェル関数内の位置パラメ
 ータと特殊パラペータ「$#」は、一時的にシェル関数の『引数』とその個数で置
 き換えられる。このため、位置パラメーターと特殊パラペータ$#はシェル関数内
 のみで有効。

あと、shの場合「function」は使えない、またシェル関数名の後ろに「()」がないと syntax error

$ cat bug.sh【修正版】
bug_version() { ← shの場合「function」は使えない、シェル関数名の後ろに「()」がないとダメ
echo "argument $1 can't handle in function"
}
bug_version $1 ← シェル関数に引数として渡した例
echo "argument $1 can handle out of function"
$ sh bug.sh
argument arg can't handle in function
argument arg can handle out of function
0040名無しさん@お腹いっぱい。2015/09/06(日) 17:59:13.35
引数はそういうものです
bug_versionを引数無しで呼び出してるので$1には何も設定されません
0041392015/09/06(日) 18:00:18.46
【訂正】
$ sh bug.sh arg
argument arg can't handle in function
argument arg can handle out of function
0042名無しさん@お腹いっぱい。2015/09/06(日) 19:34:01.02
>>38
まぁ Linux 限定だけど、

function bug_version {
echo "argument $(cat /proc/$$/cmdline | xargs -n1 -0 | sed -n 3p) can handle in function"
}

なんてするといいかも
0043名無しさん@お腹いっぱい。2015/09/06(日) 19:39:35.79
愚かにも引数忘れてた
みんなありがとう
コードが綺麗になった
0044名無しさん@お腹いっぱい。2015/09/09(水) 19:11:24.39
質問です。

grep "aaa\|bbb" はokなのに、grep "aaa\&bbb" はなぜ
だめなんでしょう?
■ このスレッドは過去ログ倉庫に格納されています