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

■ このスレッドは過去ログ倉庫に格納されています
2021/10/05(火) 22:49:30.91ID:KsbWuyFp
シェルスクリプトに関する総合スレッドです。

全般
・荒しは無視しましょう。
・丁寧な姿勢を心掛けましょう。
・ネチケット(死語)を意識しましょう。
・「○○(他の言語)でいいやん」は禁止。他のスレに行ってください。
・「POSIX原理主義」「ユニケージ」「USP研究所」はPOSIXとUnixを曲解し
間違ったシェルスクリプトを広めている宗教です。洗脳されないようにしてください。

前スレ: シェルスクリプト総合 その36
https://mevius.5ch.net/test/read.cgi/tech/1614212414/

関連スレ
・【Bash】Windows Subsystem for Linux【WSL】11
https://mao.5ch.net/test/read.cgi/linux/1627507889/
・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/
・過去UNIXで使われていた ksh というシェルについて
https://mevius.5ch.net/test/read.cgi/unix/1582358403/
・【POSIX】UNIXプログラミング【BSD】 [転載禁止](c)2ch.net
https://mevius.5ch.net/test/read.cgi/unix/1443103705/
・おまえら! shell は何を使っているんですか?
https://mevius.5ch.net/test/read.cgi/unix/1012330865/
2022/04/21(木) 22:29:49.14ID:Q2Q995JA
{ for _ in {1..10};do read l; echo "$l"; done; tail; } < <(grep 22-04-20 tmp)
2022/04/21(木) 22:37:33.49ID:Q2Q995JA
grep 22-04-20 tmp | tee >(head) >(tail) >/dev/null
2022/04/22(金) 01:40:46.85ID:p9VEf+/q
lsの日時の書式をyyyy/mm/dd hh:mm:ss固定にしたいのですがどっかに設定あるんでしょうか
2022/04/22(金) 02:32:55.95ID:SxzvmxoM
>>688
これ動くような気もするけど、エッジケースの詰め合わせみたいで関心するわ…ぜひ明日試したい

teeはプロセス置換への分配を均等に進めるのか?
head/tail でなければ入力も出力も数ブロックのバッファ単位で入り交じるはずだけど、バッファ単位に収まる10行のhead/tailの出力は一塊で吐かれるはず、つまりhead→tail/tail->headのいずれか
先頭だけ舐めるheadの方がtailより先に処理を終えるからhead->tail、の出力になるのだろうか?
2022/04/22(金) 02:54:12.16ID:AtJxm6z2
tee, head, tailの実装とバッファリングモード、入力データの素性の全てに依存してそうなヤバさ
2022/04/22(金) 03:06:07.22ID:xNmupzsw
とりあえず手元のandroidとかいう玩具で

GNU bash, version 5.1.8(1)-release (aarch64-unknown-linux-android)

$ seq 100 | tee >(head) >(tail) >/dev/null
91
92
93
94
95
96
97
98
99
100
1
2
3
4
5
6
7
8
9
10
2022/04/22(金) 03:07:10.32ID:xNmupzsw
あとコマンドはgnuの
2022/04/22(金) 03:15:13.30ID:fjQN0Ax7
seq 100000にしたらheadが勝ったわw
2022/04/22(金) 03:34:30.65ID:SxzvmxoM
入力が小さいときに限っては、teeも実質引数に一回渡したきりだからheadの速さも関係ないんだろうね
seqの引数を二分していけば均衡して、結果はランダムになりそう
2022/04/22(金) 05:38:09.18ID:rkPZZrpS
awk -v N=10 '{ if (NR <= N) print $0; buf[NR % N] = $0 } END { for (i = (NR - N + 1 > N + 1 ? NR - N + 1 : N + 1); i <= NR; i++) print buf[i % N] }'
2022/04/22(金) 09:43:04.69ID:9We3r0d8
つまりさ、複数のコマンドを使って
効率的に処理する方法はないってことでしょ?
>>696みたいにするしかない
2022/04/22(金) 11:42:06.75ID:bWbp9a44
seq 100 | pee head tail

peeでだめなん?
699デフォルトの名無しさん
垢版 |
2022/04/22(金) 11:52:54.17ID:IqSZbuIe
>>689
ls −l −−time−style=+'%Y/%m/%d %H:%M:%S'
をaliasにでも登録しておく
2022/04/22(金) 12:15:37.42ID:IW9biBQV
>>697
そもそもgrepが律速なんだから効率とか野暮だけど、あえて言うなら

元のファイルがダンプしてしまえるならストレージは食うが終端にシークしてしまうのが最速だし、ストリーム処理なら初めの10行プリントする自明な処理の後、10行のバッファを保持して終端が見えるまでひたすら読みまくるしかアルゴリズムはないわけで

それはsed N;N;...でもなんでもいいが、timeするまでもなく10行保持して読み捨て専用マシーンとしてガリガリチューンされてるtailを使うのが最速に決まっとるがな
2022/04/22(金) 12:22:41.13ID:IW9biBQV
変な流れになってるのは>>688という爆弾に完全に食われてしまったからな…
俺にも挙動が予測不能過ぎて興味が尽きない
2022/04/22(金) 12:37:37.28ID:QL3esWpR
>>695
seq 10001 | tee >(tail -10000) >(head -10000) >/dev/null
を実行しても、headが前半、tailが後半と期待どおりに出力されるんで、問題ないんちゃう?
headは頭から行単位に出力、tailは終端に達してから出力、やと思うとそれでいい気もするし。

>>692は知らん!w
2022/04/22(金) 12:45:37.78ID:SxzvmxoM
並スペックのx86-64Debian/bash5/coreutils環境で問題のを検証

>>692
うちではseq 100だとheadが勝った、なおheadとtailを交換しても同じ

10000(適当)でも大体同じ結果が出る、そもそも再現性あるの?と思って十回くらい再実行してたら
1 2 3 4 5 6 7 99991 9992 9993 9994 9995 9996 9997 9998 9999 10000 8 9 10
という入り交じるケースを発見したw
2022/04/22(金) 13:13:46.93ID:SxzvmxoM
head or tailだけにコイントスってか(裏でも表でもないが)
https://i.imgur.com/uQBk3cx.jpg
2022/04/22(金) 13:21:40.45ID:4sYij9Dr
バックグラウンドの割り込み遅延やその時点での負荷が影響するだろうから、エントロピー源に出来るな
もっとも一様乱数に近付けるにはおま環固有の定数を探す必要はあるが

マウスグリグリで乱数吐く/dev/randomと原理的には同じもの
2022/04/22(金) 13:48:09.59ID:MIuZAVWA
そもそもteeから非同期に投げたプロセスが順序良く出力することを期待するのがおかしいわけで
何のコマンドでもいいが、それを暗喩する名前のheadとtailというチョイスがツボに嵌まって面白い
というか>>688は狙ってやってるだろ

pidやマウス座標とか拾って改善目指すとかは無粋
2022/04/22(金) 14:06:12.36ID:SxzvmxoM
字面とその挙動、足すことも引くことも躊躇われる簡潔さ
完成し尽くされてるよな
今スレのベストコマンド賞にノミネートしたい
2022/04/22(金) 14:37:33.47ID:E3Z2WeTR
ユーモア部門なw
プロセス置換がposixで無いのだけが惜しいが、一番面白いワンライナーなのは間違いない
2022/04/22(金) 17:37:52.50ID:QL3esWpR
>>703
tailのほうにsleep 0.1でも入れとけば充分安定するな。
2022/04/22(金) 17:51:31.59ID:XoRdeeG7
そこまでやるならもういっそ行番号振って最後にソートしろよ…
2022/04/22(金) 17:55:41.86ID:Llc7G82k
というか、気紛れさが可愛いという話なのに安定させてどうする
2022/04/22(金) 19:07:59.33ID:t4x32peS
もうとっくに解決してるので…
爆弾落としてった誰かが悪い

>>687でいいと思うが、あえて添削するとすれば、まずコマンド置換は不要
grep pat file | { for i in {1..10}; do read line; echo "$line"; done; tail; }

再利用したいならパラメトライズが面倒なブレース展開を避けるべき(パラメータ展開より先)
{1..10} -> $(seq $n)

もちろんwhileでカウントしてもいい、どちらの版も適当なファイルで取り敢えず動作確認済
2022/04/22(金) 19:10:33.14ID:t4x32peS
まちがい
✗コマンド置換

✔プロセス置換
です
2022/04/24(日) 09:09:54.95ID:tpsbRsIR
質問です

if [-z $cmwt ]の-zは何なん?
2022/04/24(日) 09:26:53.94ID:R/F29R42
プーチン親衛隊
2022/04/24(日) 10:21:41.54ID:TEfYtyVL
$ man [
2022/04/24(日) 10:30:43.78ID:tpsbRsIR
>>715
そういうのいらないっす.

>>716
[ がコマンドなんすね そのオプション -z the length of STRING is 0 だとfalse?
2022/04/24(日) 10:41:04.67ID:agfo7zfZ
bash$ help test | grep -A1 -e '-z'
719デフォルトの名無しさん
垢版 |
2022/04/25(月) 23:07:17.30ID:OWEpx0GO
>>717
あのさ、シェルスクリプトをちゃんと勉強しろよ!
「入門UNIXシェルプログラミング―シェルの基礎から学ぶUNIXの世界」という本があるんだけど、これを読めば何もかもわかるよ。
2022/04/26(火) 02:19:34.78ID:JTn9J471
UNIX シェルスクリプト・コマンドブック 第3版、山下哲典、2015
2022/04/26(火) 09:41:05.59ID:abeO/U+d
[ がコマンドで、ゆえに直後にスペースが必要
というのは初心者が見落としやすいところではある
2022/04/26(火) 12:36:05.16ID:60BzfgWB
シェルスクリプトの基礎をすっとばして
いきなりコマンドの使いこなしから始めましょう
みたいなのは害悪だと思う
シェル芸から始めるんじゃなくて、シェルスクリプトを勉強すべき
723デフォルトの名無しさん
垢版 |
2022/04/26(火) 12:54:52.42ID:uKDaCZCW
言い出したら切りがないけどコンピューターの仕組みからやるべき
2022/04/26(火) 14:33:11.23ID:QfJATbip
もうシリコンの採掘からやれや!
2022/04/26(火) 18:21:48.39ID:TDP9zkh+
多結晶シリコンのインゴットは作ったことあるわ
2022/04/26(火) 18:31:04.23ID:lyut1+Mp
その辺の河原で拾った事ならあるな
727デフォルトの名無しさん
垢版 |
2022/04/26(火) 19:24:30.73ID:hbZUgTG0
金の採掘もやっとくか…
2022/04/26(火) 19:31:31.14ID:9HhSqCwG
今年は天候不良で収穫量が少ないとか
2022/04/26(火) 19:32:36.15ID:G+JzaZJD
まずはマニュアルくらい一通り読まんとな
俺は座り無精なのでマニュアルだけ読んでマスターした気になってる言語の方が多いくらい()
2022/04/28(木) 23:43:17.98ID:a4NDWJu+
vimでshebangを自動で入力してくれる機能ありますか?
2022/04/29(金) 00:29:58.42ID:lUnjMOza
#!/usr/bin/env ruby
2022/04/29(金) 00:34:04.74ID:gP3ffc3T
スレ違いだと思うけどまあ一応
:autocmd BufNewFile *.sh [コマンド]

put='#! /path/to/sh'
多分dieとかgetoptとかtrap含めたテンプレを用意して日付とかファイル名とかお前の名前とか置換
r /path/to/tmpl.sh | s/__DATE__/\=strftime('%Y-%m-%d')/

未テスト
2022/04/29(金) 00:49:51.62ID:iZ0Puaoh
>>732
ありがとうございます、:autcmdですか
2022/06/21(火) 19:32:07.61ID:0jGPid+s
スペースを含む複数のファイル名を一括でリネームしたいんですが、上手い方法はありますか?
スペース無しならfind+sed+xargsで行けるのですが
735デフォルトの名無しさん
垢版 |
2022/06/21(火) 20:31:37.09ID:q62JFBwI
\x20で行けたりしないかな
736デフォルトの名無しさん
垢版 |
2022/06/21(火) 20:45:32.09ID:eKSiaONm
findのオプションでprint0とかしたらいけないんだっけ?
2022/06/21(火) 21:06:17.83ID:EjbRTWsP
>>734
そういうのsed使って加工するとだいたい壊れるw
ファイル名を置換するシェルスクリプトを作れ
あとはそれをfind -execで呼び出せばいいだけ
2022/06/21(火) 21:13:42.89ID:EjbRTWsP
それからあとはどんなリネームをしたいのかを書くこと
2022/06/22(水) 19:28:36.54ID:EcTc17L7
Ruby で作ってみた

ファイル名に含まれる全ての半角空白を、アンダーバーへ変換する。
ただし、DryRun なので実際には変更されません。
ファイル名が変更された時に、既に同名のファイルが存在する場合は、エラーとする

require 'fileutils'
require 'set'

# 絶対パスのディレクトリ名の後ろに、* を付けること!
# . で始まる、隠し directory, file を除く
glob_pattern = "C:/Users/Owner/Documents/test/*"
target_dir = File.dirname( glob_pattern ) # ディレクトリパスだけを取り出す

# そのディレクトリ内の全てのファイル名だけを抜き出す
old_filenames = Dir.glob( glob_pattern ).map { |full_path| File.basename( full_path ) }
old_filenames_set = Set.new( old_filenames ) # エラー処理用に、set にも入れる

# ファイル名に含まれる全ての半角空白を、アンダーバーへ変換する
new_filenames = old_filenames.map do |filename|
new_fn = filename.tr( " ", "_" )
# ファイル名が変更された時に、既に同名のファイルが存在する場合は、エラー!
if new_fn != filename
raise "ファイル名 #{ filename } が重複します!" if old_filenames_set.include?( new_fn )
end

new_fn
end

次へ続く
740739
垢版 |
2022/06/22(水) 19:29:18.14ID:EcTc17L7
前の続き

# ファイル名を変更する
old_filenames.zip( new_filenames ) do |old_filename, new_filename|
# 変換されなかったファイルは、処理しない
next if old_filename == new_filename

old_path = target_dir + "/" + old_filename
new_path = target_dir + "/" + new_filename

FileUtils::DryRun.move( old_path, new_path)
end
741デフォルトの名無しさん
垢版 |
2022/06/22(水) 21:31:19.80ID:r+zxbhox
スペース含みの対処はレコード区切りを'\0'にすること
(普通だったら'\n'区切り)

find ... -print0 | sed -z 's/...//' | xargs -0 ...

renameが目的なら1レコードをsedで2レコードに分割して、
xargs -0 -n2 mv で受け取ることになるんじゃない?
パイプに流れてるものを見たけりゃxxdでも使えばいい
742デフォルトの名無しさん
垢版 |
2022/06/22(水) 23:59:58.34ID:qmaAVV4a
なんだそれ
2022/06/23(木) 00:51:47.61ID:p4V7vEeM
>>734
どんなリネームかによるけど、renameコマンドは?
2022/06/24(金) 22:25:26.43ID:ah9fFKb9
for n in { 1 2 3 }
do
echo $n
done
ってバグ?
745デフォルトの名無しさん
垢版 |
2022/06/24(金) 22:30:30.37ID:wjFt6G0b
手元のshellで気に入らない動作でもしたのか?
誰かが書いたコードがおかしい話か?
2022/06/24(金) 23:20:53.20ID:K5vj26OZ
ループに{}も含めたいのならバグじゃないし
含めたくないならバグかもしれない
知らんがな
2022/06/25(土) 00:54:30.97ID:3Gjf2Ej1
バグだったみたいです
2022/06/25(土) 01:42:22.54ID:+sGuzAtV
波括弧って文法上意味を持つ(フォークしないグルーピング)から含まれないのは正しい挙動だろう
2022/06/25(土) 10:28:24.73ID:zmRipdPc
え?バグダッドが見たいだって?
2022/06/25(土) 10:29:40.74ID:zmRipdPc
>>748
波括弧はただの予約語やで
2022/06/25(土) 16:56:56.58ID:+sGuzAtV
>>750
よくわからん指摘
予約語か文法として意味持つかは直交する話でしょう
2022/06/25(土) 19:46:30.70ID:zmRipdPc
>>751
その他の予約語 if

お前 echo if が、文法上ifという意味を持つなんて思うの?w
2022/06/25(土) 19:49:57.18ID:zmRipdPc
予約語が特殊な意味を持つのは
コマンドの最初に使ったときだけ
わからんかねぇw
2022/06/25(土) 21:07:44.33ID:K9JamG/I
えっ?
2022/06/25(土) 21:39:41.82ID:RwCs863z
man bashにも、{ }には注意しろ、て書いてあるくらいやからな。
2022/06/26(日) 12:28:30.09ID:HMqwJiMU
>>753
いかれてやがる
2022/06/26(日) 19:26:23.55ID:7NgSBfAB
お前が無知なだけやろw
{ } は文法上は特別な意味を持たない
758デフォルトの名無しさん
垢版 |
2022/06/27(月) 15:46:57.73ID:CskE0rDG
外出しの関数ファイルってどんな名前にしてる?
特に拡張子
2022/06/27(月) 16:49:42.17ID:qAroFeWq
関数が書いてあってsourceで読み込むファイル?
名前は何が聞きたいのか知らんけど拡張子は
POSIX準拠で作るときは.shで、bash用なら.bashかな
760デフォルトの名無しさん
垢版 |
2022/06/27(月) 18:23:34.81ID:CskE0rDG
>>759
そそsourceで読み込むやつ
やっぱそんな感じだよね

前に参画してたプロジェクトでは.prfだったから最初?ってなった
ちなみに変数外出しするなら?
2022/06/27(月) 20:23:09.07ID:qAroFeWq
変数だけ区別する必要ないやろ?
.shか.bash
2022/06/28(火) 01:11:34.56ID:Dv09yGDf
コマンドとしては使えないスクリプトファイル、ということで、拡張子を別にしたい気持ちはわかる。
検索しやすくなるしな。
2022/06/28(火) 05:39:12.64ID:L08FVbEp
関数しか書いてないやつはコマンドとして使えないんだから
それと同じでいいやん
764デフォルトの名無しさん
垢版 |
2022/06/28(火) 10:28:28.56ID:ucMrCo9H
>>762
なるほどそういう考えか
765デフォルトの名無しさん
垢版 |
2022/07/01(金) 00:50:47.17ID:oYJ8x66X
独自拡張子は嫌われる
2022/07/02(土) 11:14:35.24ID:EoiiwDBr
bashというかシェル全般について質問です

シェル内で変数定義(例えばTEST="test")して
Java(jar)プログラムを呼び出してその中で環境変数(TEST)を
取得すると値"test"が得られます
シェル内の変数とは環境変数と同義なのでしょうか?
単なるスコープの違いでしょうか?
2022/07/02(土) 12:12:57.61ID:UMJkSd0D
どっかで export TEST されてるんじゃ
2022/07/02(土) 15:06:57.46ID:EoiiwDBr
>>767
語弊があったかもしれませんが
シェル内で変数定義とJavaプログラムの呼び出しをしています
具体的には以下のような感じです

・sample.bash
#!/bin/bash
TEST="test" # この変数が環境変数と同義?
/usr/bin/java -jar Sample.jar
exit 0

・Sample.jar (Sample.java)
public class Sample {
 public static void main(String[] args) {
  String str = System.getenv("TEST"); // 値"test"が取得可能
  System.out.println(str);
 }
}
769デフォルトの名無しさん
垢版 |
2022/07/02(土) 15:46:05.19ID:5r3z96xh
そのシェル以外のどこかでexportされてる可能性もなくはない
2022/07/02(土) 15:52:50.74ID:UMJkSd0D
>>768
sample.bash を起動するシェルで unset TEST してから実行してみて
docker で試したけどちゃんと null が出力されたよ
2022/07/02(土) 16:06:22.74ID:0FvUmWjS
UNIXという生き方
2022/07/02(土) 16:07:36.00ID:EoiiwDBr
>>769
>>770
すみません見落としている箇所があって
きちんとexportしていました
そりゃそうですよね…
2022/07/02(土) 16:12:42.46ID:UMJkSd0D
>>772
ええんやで
解決したようでよかった
2022/07/02(土) 18:48:20.54ID:s0/GJKKm
しかし普通はそんなのが定義されていたからって
だからなんだ?っていう話なんだよな
775デフォルトの名無しさん
垢版 |
2022/07/12(火) 23:34:22.21ID:gA1pIjpV
引数解析にgetoptsってどう思う?
2022/07/13(水) 12:19:30.78ID:EtP8dxEe
Ruby では、コマンドライン引数の処理に、OptionParser を使って、

short/long option を定義していく
2022/07/13(水) 12:39:57.76ID:Tiof6JBH
そうなんだすごいね
778デフォルトの名無しさん
垢版 |
2022/07/13(水) 12:47:37.07ID:C1CGdRc+
>>776が見えない
2022/07/13(水) 14:35:32.25ID:4m9BBmhO
そういう人は多い
どこにでも現れるのでね
2022/07/13(水) 14:41:02.34ID:7GbSF+de
見えないというのなら見えるようにしてあげよう

ルビーでは、コマンドライン引数の処理に、おぷしょんぱーさー を使って、

short/long option を定義していく
2022/07/13(水) 17:17:56.15ID:ygLQXjBv
見えるようになってない
2022/07/13(水) 17:39:24.41ID:SQcVdjvN
なんで見えないのにレスできるんだよwww
2022/07/13(水) 18:23:16.73ID:ccIVitkd
>>775
好きにすればいいと思う
2022/07/13(水) 18:48:04.93ID:EtP8dxEe
Ruby のoptparse なら、
ruby ./a.rb -a -b1 --foo --bar x

require 'optparse'

# ARGV.replace %w(-a -b1 --foo --bar x)

opt = OptionParser.new
p params = opt.getopts( ARGV, "ab:", "foo", "bar:" )

#=> {"a"=>true, "b"=>"1", "foo"=>true, "bar"=>"x"}
785デフォルトの名無しさん
垢版 |
2022/07/13(水) 19:41:24.35ID:8ZGfs65M
>>780も見えなくした
786デフォルトの名無しさん
垢版 |
2022/07/14(木) 16:46:11.67ID:mBJkiOUt
>>783
分かった
ありがとう
2022/07/14(木) 16:48:02.99ID:rMT+3vzc
どうしたまして
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況