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

■ このスレッドは過去ログ倉庫に格納されています
2020/08/21(金) 15:17:55.64ID:mArnj/tT
シェルスクリプトに関する総合スレッドです。

全般
・荒しは無視しましょう。
・丁寧な姿勢を心掛けましょう。
・ネチケット(死語)を意識しましょう。
・「○○(他の言語)でいいやん」は禁止。他のスレに行ってください。

シェルスクリプト総合 その33
https://mevius.5ch.net/test/read.cgi/tech/1584893550/
2020/08/21(金) 15:18:16.96ID:mArnj/tT
・特記なき場合、POSIX準拠シェルが既定です(古きBourneシェルはほぼ絶滅しました)
 POSIX準拠シェルは(d)ash, bash, zsh, (m)ksh, yash, posh, (p)boshです
 参考 https://unix.stackexchange.com/questions/145522/
 特定のシェルの専用機能に依存する場合は明示しましょう(特にPOSIX準拠シェルではないfish, (t)csh等)
・デフォルトシェルのシバンはBourneシェル時代からの伝統で#!/bin/shを使用します。ただしその実体はOSによって様々です
  Debian系 … dash   CentOS系 … bash   Alpine … ash(busybox)  Android … mksh
  FreeBSD … ash   Solaris,OpenBSD … ksh
  macOS … bash(Single UNIX Specification準拠のために一部動作が異なる)
・ログインシェルは/bin/shでない場合があります。例 macOS … zsh
・シェルスクリプトは可搬性を持たせるために可能な限りPOSIXに準拠しましょう
 仕様 http://pubs.opengroup.org/onlinepubs/9699919799/
 参考 https://en.wikipedia.org/wiki/POSIX
・bash依存はなるべく避けましょう。自覚なきbashism。シバンが#!/bin/shなのにbashに依存する構文を使っていませんか?
 #!/bin/shを使うならシェル依存は厳禁です。bash依存するなら#!/bin/bashです
・BourneシェルはPOSIX標準化前に主にUNIXで使われていたシェルで多くの亜種が存在します
 Bourneシェル≒Version 7 UNIXのshに一番近いのはOpenSolaris由来のHeirloom Bourne Shell、次点でSchily Bourne Shellのoboshです
  Heirloom Bourne Shell: sh http://heirloom.sourceforge.net/sh.html
  Schily Bourne Shell: obosh http://schilytools.sourceforge.net/bosh.html
 歴史的資料 https://www.in-ulm.de/~mascheck/
・csh/tcshでのシェルスクリプトは*まったく推奨しません*
  参考 http://www.speech-lab.org/~hiroki/csh-whynot.euc
・Linux/UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。Manページや各種リンクを見ましょう
 aproposやman -kでそれらしい単語による簡単な検索もできます
・ワイルドカード・パターンは正規表現ではありません。正規表現の話題はスレ違い(正規表現スレへ)
・シェル芸はシェルスクリプトとは異なります
・シェルスクリプトのことをシェルってゆうな
2020/08/21(金) 15:19:27.93ID:mArnj/tT
関連スレ

【Bash】Windows Subsystem for Linux【WSL】8
https://mao.5ch.net/test/read.cgi/linux/1590742701/

Bashでプログラミング [転載禁止](c)2ch.net
https://mao.5ch.net/test/read.cgi/linux/1443885102/

シェルスクリプト総合 その28
https://mevius.5ch.net/test/read.cgi/unix/1533154936/

zsh その7
https://mevius.5ch.net/test/read.cgi/unix/1337844883/

【POSIX】UNIXプログラミング【BSD】 [転載禁止](c)2ch.net
https://mevius.5ch.net/test/read.cgi/unix/1443103705/
2020/08/21(金) 15:25:17.16ID:MuUIpq44
>>1
おっつん
5デフォルトの名無しさん
垢版 |
2020/08/24(月) 18:01:20.80ID:xVB6pD3/
こんにちは
Macでzshを使っています
フォルダに

memo20200810.txt
memo20200817.txt
memo20200824.txt

のようなファイルがあったとして(週に1つずつ増える)
最新のファイルをechoで見たいとしたらどうするのがいいでしょうか???
2020/08/24(月) 18:06:26.10ID:xVB6pD3/
すみませんechoではなくcatでした
別にコマンドは何でもいいので最新のテキストの内容を見る方法を知りたいです
2020/08/24(月) 18:08:35.17ID:eDLiikcy
cat "$(/bin/ls *.txt | tail -1)"
2020/08/24(月) 18:14:51.49ID:xVB6pD3/
ありがとうございました!
9デフォルトの名無しさん
垢版 |
2020/08/24(月) 19:06:43.25ID:8Ar+AlN+
ファイルが大量にあった場合には大きい順でソートして1行目を取り出すみたいに書いた方が速くないか?
10デフォルトの名無しさん
垢版 |
2020/08/24(月) 19:12:31.00ID:8Ar+AlN+
ただし ls で引数に指定するのはディレクトリ。
2020/08/25(火) 08:17:19.49ID:kX+0EEJG
>>7
ちなみにlsだけフルパスなのは? lsがエイリアスである可能性を考慮とか?
2020/08/25(火) 08:57:33.67ID:c6c4SV8K
Unixで「複数のパスを区切る」といえばコロン区切りが普通だと思うんだけど
(例えばPATH,CDPATH,NLSPATHとか)
POSIXの
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
でも言われている通りコロンが含まれているパスを指定することができない。

もちろん自分で勝手にPOSIXを逸脱して,バックスラッシュでコロンを
エスケープする,みたいなことをしてもいいんだけど,
なるたけ標準に合わせたい。

環境変数で複数のパスを指定するときに,
コロンを含めるようにしているユーティリティの例とか知らない?
2020/08/25(火) 09:30:33.15ID:lHpt9rtN
PATHがコロン含められないのにコロン使えるようにするの?
チャレンジャーだなw

Unixはパスに使えない文字を決めたほうが良かったと思うね
MS-DOS/Windowsはちょっと多すぎだけど
2020/08/25(火) 12:32:57.49ID:c6c4SV8K
>>13
Windowsだとドライブレターにコロンを使ってるから
PATHの区切りは;ですね。
2020/08/25(火) 14:21:00.18ID:qvclnJmh
>>14
シェルスクリプトには関係なくね?
2020/08/25(火) 14:22:05.05ID:qvclnJmh
そういや環境変数名に記号とか改行とか使えるの知ってる?w
2020/08/27(木) 12:47:09.11ID:Di05+wlc
コマンドの戻り値を反転させたい、つまり0のときは非0に、非0のときは0に変えたいんだけど、どうすれば?
set -e状態のスクリプトで、特殊なコマンドを使いたい場合に。

また、makeで使うときにmake専用の記法(-とか@とか)がもしあればそれも。
2020/08/27(木) 13:37:00.71ID:Q9F08mvx
>>17
if [ $? -eq 0 ]; then
 exit 1
else
 exit 0
fi

すればいいと思うけど、困ってる点は何?
2020/08/27(木) 13:56:01.63ID:Di05+wlc
>>18
set -e状態やmakefile中では、コマンドが終了した時点でエラー中断する。
なので、$?を参照するところまで至らない。
2020/08/27(木) 14:11:33.44ID:Di05+wlc
ちなみに、makefileの場合は、次のように一行にまとめてしまえばごまかすことはできるが、set -eスクリプトだとやっぱりダメなもよう。

コマンド; test $? -ne 0
2020/08/27(木) 14:24:40.22ID:eXOTJM+N
!
2020/08/27(木) 15:13:00.41ID:Q9F08mvx
>>19
まあ大体そうなんだろうとは思ったが
どういうときにコマンドの戻り値を反転させたいのか気になるけど
処理をmain関数に入れてしまってこれでできるはず

( main ) && return 1
return 0

! ( main ) でも一応良いはずなんだけど ifを使わずにコマンドの頭に
!をつけるだけだと動かないシェルがあった気がする
今回はサブシェルが間に入っているから大丈夫かもだけど

あとは、思いつきだけどこんな感じでも出来る気がする

#!/bin/sh
set -e
trap 'exit $(($? == 0 ? 1 : 0))' EXIT
任意のコマンド
2020/08/27(木) 15:13:43.83ID:Q9F08mvx
ちなみにmakefileは知らんw
24デフォルトの名無しさん
垢版 |
2020/08/27(木) 15:30:52.02ID:aM8Ck5Vz
0/1の二択なら1から引けばいいじゃんね
2020/08/27(木) 15:33:26.32ID:Q9F08mvx
set -eでエラー終了した時は$?が1とは限らん

trap 'exit $(($? == 0 ? 1 : 0))' EXIT
trap 'exit $(($? > 0 ? 0 : 1))' EXIT # 一文字短縮化w
2020/08/28(金) 15:22:32.20ID:hYmDe1I0
>>21
>>22
ありがとう。
コマンドラインの前に「!」を書けばいいのか。
manページを確認すると、「logical negation」とあったから、こちらの期待どおり。
2020/08/28(金) 19:08:43.38ID:0gWrnmZ1
trap 'exit $(($? > 0 ? 0 : 1))' EXIT
これいいね
2020/08/29(土) 14:16:28.94ID:fysUNitN
MirBSDの記事として書き込まれてたけど
このスレの前々スレくらいでもちょっと議論されてた
「ASCII区切り文字による表形式」についての話

https://www.mirbsd.org/permalinks/wlog2020_e20200620.htm#e20200620_wlog2020
2020/08/29(土) 15:32:00.60ID:tFn2MGZe
>>28
あー、その記事読んだ。FSってフィールドセパレータだと思っちゃうよねw
たまたま俺は、レコードとフィールドと、ファイル区切りもいるかなぁ?って
考えながら探してたから、お、4つもあるじゃんって感じで気付いたが
30デフォルトの名無しさん
垢版 |
2020/08/29(土) 16:27:42.59ID:2GmTjly/
>>16
知ってる。
31デフォルトの名無しさん
垢版 |
2020/08/29(土) 16:39:43.91ID:2GmTjly/
>>17
シェルによって書き方違うかも知れないがこんな書き方も可能。

if コマンド [引数 ...]
then
 exit 1
else
 exit 0
fi

ほぼ >>18 と同じだが、コマンドを if の直後に書けばそのまま戻り値の判定ができる。

こういう書き方もできる。短い場合はこれでも良いかも。(でも後で見て分かり辛くなるかな?)

コマンド [引数 ...] && exit 1 || exit 0

2行に分けても行ける。exit 1 の方が実行されたら下の行には行かないので。
こちらの方が見た目は分かり易いかな。

コマンド [引数 ...] && exit 1
exit 0
2020/08/29(土) 16:42:17.42ID:2GmTjly/
あ。上の方からゆっくり読んで下まで読まずに書いたら途中で色々と話が進んでいたorz
2020/08/30(日) 18:43:29.75ID:CLO3al/P
https://mevius.5ch.net/test/read.cgi/tech/1537584801/206
この問題のレベル2を実装できないw

レベル1は
foo() { set -- $2 $1 $(shift 2; printf ' %s' "$@"); bar "$@"; }
↑こんな感じのが正解の一つだと思うんだが,
これだと
foo 1 2 3 4 '5 includes space'
という引数を指定した場合に
$ foo 1 2 3 4 '5 includes space'
begin
2
1
3
4
5
includes
space
end
というような出力になってしまう。
2020/08/31(月) 12:38:22.81ID:pjiHotrY
age
2020/09/02(水) 11:33:18.91ID:ifuz91bD
シェルスクリプトマスターしてしまったので
シェルスクリプト難しいって言ってる人が
何が難しいのかわからなくなった

シェルスクリプトが難しいんじゃなくて
初心者だから難しいだけなんじゃ?
36デフォルトの名無しさん
垢版 |
2020/09/02(水) 19:16:56.69ID:orWCnyGy
>>33
age
37デフォルトの名無しさん
垢版 |
2020/09/03(木) 02:22:39.28ID:weiyro1+
>>33
いくつかやり方があると思うがヒントな

位置パラメータが 1 2 3 4 5 の状態から
1 2 3 4 5 2 1 3 4 5 を作り出すことができれば
あとはshift 5をするだけで
2 1 3 4 5 にすることができる

この問題を解くカギは、終了条件をどうするか?なんだよ
38デフォルトの名無しさん
垢版 |
2020/09/03(木) 02:23:25.90ID:ZRdxhfh3
1 2 3 4 5  2 1 3 4 5 を作り出すことができれば

スペース入れたつもりだったが見やすくならなかったな
2020/09/03(木) 21:49:28.77ID:cH7nhQ1J
>>37
Thx
考えてみる
2020/09/03(木) 23:57:53.85ID:BJh39Y3Y
補足 わかると思うけど

この問題を解くカギは、「ループの」終了条件をどうするか?なんだよ
2020/09/06(日) 11:36:07.13ID:r+7yP+3C
>>37 >>40
ちなみに >>33 の解答でも
setやshiftを使ったりしてうまいこと
引数処理をしてはいる。
2020/09/06(日) 14:08:50.79ID:B3LMKUW8
もう自演にしか見えないw
2020/09/06(日) 20:01:46.98ID:7hbRm2sU
前スレ止まってると思ったら埋めずに分裂してたんかい
2020/09/06(日) 20:55:56.09ID:racdSqu4
>>41
できたかニャ?
2020/09/07(月) 13:21:21.27ID:77IwCGLU
>>44
できた。
結局 >>37 のヒントには全く頼らなかったわw

eval "set -- \
$(printf "'%s' \\\\\n" "$2" "$1"
shift 2; while [ $# -gt 1 ]; do printf '%s\n' "$1" |
sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"; shift; done
printf '%s\n' "$1" |
sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/")"
46デフォルトの名無しさん
垢版 |
2020/09/08(火) 10:49:07.66ID:4xL00uJx
申し訳ないですが誰か教えてください。
以下のような感じで処理をしたいのですが
a.sh(rootで実行)
#!/bin/bash
#処理
#postgresでb.shを実行
su - postgres -c "bash パス/b.sh `$1`"

echo "b.sh完了"

#testでc.shを実行
su - test -c "bash パス/c.sh"
echo "c.sh完了"

exit 0;

b.sh(postgres)
#!bin/bash
#複数処理
exit 0;

これをやるとb.shの一番最初の処理は実行できるのですが
2番目の処理からがエラーで実行できません。
postgresにてb.sh単体で処理を動かすと問題なく動かすことが出来るのですが・・・

このb.shをrootのa.shからpostgresのb.shを呼ぶ方法を教えていただけないでしょうか。
またシェルを分けずに、一貫してやった場合てどうやって途中でユーザ切り替えするのでしょうか?
申し訳ございませんが教えてください・・・
2020/09/08(火) 11:14:25.07ID:ymgasiE/
>>46
なんとなく
"... `$1`"のあたりが原因なような気がする。
この状態だと引数の実行結果が空白区切りでb.shに渡される。

二番目の処理のエラーは見せられない感じ?
48デフォルトの名無しさん
垢版 |
2020/09/08(火) 11:52:32.28ID:4xL00uJx
>>47
[root@test-srv test]# ll
合計 8
-rwxrwxrwx 1 root root 216 9月 8 11:46 a.sh
-rwxrwxrwx 1 postgres postgres 115 9月 8 11:44 b.sh
[root@test-srv test]# cat a.sh
#!/bin/bash
echo "a.shの処理を開始します。"
echo "a.shのテスト出力、引数は${1}です。"
echo "b.shを実行します"
su - postgres `/home/postgres/work/work/test/b.sh ${1}`
echo "a.shを終了します"
exit 0;
[root@test-srv test]# cat b.sh
#!/bin/bash
echo "b.shの引数1は${1}です。"
echo "b.shのテスト出力です。"
echo "b.shのテスト出力です。"
exit 0;
[root@test-srv test]# ./a.sh test
a.shの処理を開始します。
a.shのテスト出力、引数はtestです。
b.shを実行します
-bash: b.shの引数1はtestです。: そのようなファイルやディレクトリはありません
a.shを終了します
[root@test-srv test]#
少し処理を変えた結果もこんな下の感じです。
[root@test-srv test]# ./a.sh test
テスト: 引数1はtestです: command not found
これはテストです
2020/09/08(火) 12:32:53.69ID:o44vEJ9h
`/home/postgres/work/work/test/b.sh ${1}`

` じゃん

su - postgres b.shの引数1はtestです。

をしようとしてるじゃん、
-bash: b.shの引数1はtestです。: そのようなファイルやディレクトリはありません
のメッセージの通りじゃん?
2020/09/08(火) 13:38:46.77ID:wSlh5XRm
いったい何がしたいんや?
バッククォートは何のため?
51デフォルトの名無しさん
垢版 |
2020/09/08(火) 13:41:35.55ID:4xL00uJx
>>49
すみませんが、知識が貧しいので
詳しく教えてください・・・
52デフォルトの名無しさん
垢版 |
2020/09/08(火) 13:44:08.25ID:4xL00uJx
>>50
単純にrootでa.shを叩いたら
postgresユーザでb.shが引数付きで呼ばれるようにしたいて感じです。

その処理がいまいちうまく組めないのです・・・
2020/09/08(火) 13:47:28.39ID:o44vEJ9h
` で囲んだのは、その時点でそれが実行されてその出力に置き換えられる。$() はほぼ等価
su - postgres `/home/postgres/work/work/test/b.sh ${1}`

su - postgres b.shの引数1はtestです。
をやろうとしてる(b.shの引数1はtestです。に b.shのテスト出力です。もあるけどな)

だから、
-bash: b.shの引数1はtestです。: そのようなファイルやディレクトリはありません
というメッセージなんだよ
su - postgres b.shの引数1はtestです。
をしようとしてるんだから

やりたいのは、
su - postgres `/home/postgres/work/work/test/b.sh ${1}`
ではなくて、
su - postgres "/home/postgres/work/work/test/b.sh ${1}"
とかだろう
54デフォルトの名無しさん
垢版 |
2020/09/08(火) 13:58:43.10ID:4xL00uJx
>>53
出来ました!
su - postgres -c "/home/postgres/work/work/test/b.sh ${1}"
という形でした。
ありがとうございました!
2020/09/08(火) 14:04:44.26ID:o44vEJ9h
ちゃんとメッセージ見ような。だいたいにおいて正しく問題点が書いてあるんだからw
2020/09/08(火) 15:16:17.47ID:wSlh5XRm
>>54
参考までに聞いてみたいが、なぜバッククォートを使おうと思ったのか?
クォートならどれでも同じだと思った?

>>55
バッククォートの機能を知らずに使うと、エラーメッセージを見てもわからんやろな。
2020/09/08(火) 15:37:36.08ID:o44vEJ9h
だが、typoでもよくみるメッセージだからな
それを実行しようとしてる、なぜなんだぜぐらいから始めないとな
2020/09/08(火) 15:59:34.51ID:7o8rcsWh
ブログはクォート関係はよく文字化けする
2020/09/08(火) 17:39:44.03ID:ymgasiE/
cshやAndroidにも対応した上で
POSIXに準拠したシェルスクリプトの書き方
(cshの場合はshで起動し直すらしい)
https://togetter.com/li/1077808?page=5
ここまでやる意義は不明w
2020/09/08(火) 20:25:26.31ID:7o8rcsWh
>>59
それは読んだことがあるが
どうももやもやしている

どういう環境でそれが必要なのかが書いてないからかな?
Androidといわれてもー
バージョンわからないしー
検証環境用意できないしーw

読んでて思うのはtogetterはツイートをまとめるだけなので
検証内容をまとめるには適してねーわ
2020/09/09(水) 10:55:40.97ID:L9ofENhq
>>60
同意。
「結局なにが分かったのか」
「解決方法はどうだったのか」
っていう,一番重要な情報もめちゃめちゃ
みにくいところにある。

しかも,まとめ主は
「あとで記事にする」と言っているのに
その後音沙汰がないし
アカウント乗り換えてる模様。
怪しすぎる。
2020/09/09(水) 11:00:38.40ID:ShrkmEVF
>>61
あとなんかシェルによってシバンの扱いが違うように書いてるように見えるんだけど
シバンを解釈するのてOSだよね?
他の言語から起動することもあるんだから
シェルはOSに丸投げしてるだけ
2020/09/09(水) 11:05:11.17ID:ShrkmEVF
だれかもうずばっと シバンはちゃんと書きましょう。
shを使うなら #!/bin/sh です。このパスがない環境はもうありません
って言ってくれないかな?w

真偽不明でタイトルだけ残ってて困る
2020/09/09(水) 11:54:49.47ID:L9ofENhq
>>63
ちょっとつっかかるけど
「このパスがない環境はもうありません」
これも根拠なくないか?

POSIXでは定められていない訳だし,
Solarisだと/bin/shはめちゃめちゃ古い。
POSIX shは/usr/xpg4/bin/shにある。
2020/09/09(水) 12:45:45.54ID:SvwSYfrG
#!/usr/bin/env sh
2020/09/09(水) 13:06:06.44ID:L9ofENhq
>>65
より非可搬。
詳細は前スレ参照。
2020/09/09(水) 17:24:48.34ID:QPd8QPwA
たまたまSolarisの環境があるから調べてみたが、

> Solarisだと/bin/shはめちゃめちゃ古い。
これはSolaris 10以前の話。古いというかPOSIX以前のBourne Shellだな。
これがSolaris 11ではkshに変わっている。

それからシステムの初期設定PATHと
getconf PATHは必ずしも同じではない

Solarisのシステムの初期設定PATHは/usr/sbin:/usr/binなんだが互換性上の理由(?)で
POSIXに準拠してない可能性があるコマンドが入っていると考えて良さそう
getconfはPOSIX準拠のコマンドということもあり、getconf PATHもPOSIX準拠のためのPATHを返す
例えば /usr/xpg4/bin/ が優先されている。ただし /usr/sbin は入ってない。Linuxでも/bin:/usr/binしか返ってこないな
だから PATH=$(getconf PATH) なんかしてしまうと fdisk が使えなくなったw
ちなみに /bin はどちらのPATHにも入ってない

getconf PATHをどう使うかもOS依存な気がするけど、Togetterまとめに書いてあるように
PATH="$(command -p getconf PATH):$PATH"
こうすることで、標準を壊すことなくPOSIX準拠に近くするという意味になるんだろう
ちなみにだけどcommandの-pオプションは古いzsh(たしか4.0あたり)で使えなかったりするけどなw

個人的にはgetconfがない環境があるのは知っていたので、そこは何も不思議はない
Togetterまとめに書いてあるPATHの初期化方法は何をやりたいのかよくわからんw
なんつーか一行にしようとして意味不明にしてるとしか思えんな。こんなんでいいやろ?

default_path="$(command -p getconf PATH 2>/dev/null ||:)"
[ "$default_path" ] && PATH="$default_path:$PATH"
2020/09/09(水) 17:25:20.59ID:QPd8QPwA
↑でこれはシバンがないほうがいいかどうかとは全く関係ない話
まぜるなや
2020/09/09(水) 18:30:55.68ID:COY4N7BF
宇宙刑事シバン
2020/09/09(水) 18:57:01.22ID:L9ofENhq
>>67
Solarisで
$ getconf PATH
するとPOSIX準拠の命令が優先されるような
設定が返ってくるのな

勉強になった。さんきゅ〜
2020/09/09(水) 18:59:49.28ID:L9ofENhq
>>67
ちなみに棘でもzshのcommand -p非対応については
触れられてたな。

あきらめてhash使ってたが。
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。