zsh その7
bash が入ってるが zsh は入ってない環境って例えばどんなの? >>545
20年前のUNIX/Linuxサーバー
10年前のならだいたい入ってると思うけど、それでもデフォルトで入ってるかどうかはわからん そうなのか。実は zsh スクリプトを積極的に書いていっていいものかと悩んでいるんだ。
他人に使ってもらうためのスクリプトは bash で書いていたが、普段使いのシェルが zsh なので
なるべくzsh を使いたい。しかし「このスクリプトを使うためにまず zsh 自体をインストールして下さい」
と言うのは避けたい。導入のハードルを上げたくない。 対話的に使うシェルとスクリプトで使うシェルは別でもいいんじゃないの 日常の作業を自動化したくてスクリプトを書くことがよくあるんです。
あと zsh の rcquotes とか zparseopts とかが便利すぎるので… 自分で答え出してるんじゃね
自分しか使わないならzshでいい
他人に使ってほしいならせめてbash >>550
はい。つまり気になっているのはデフォルトで bash が入っているが、
しかし zsh は入ってない環境が実際あるのか。ってことなんです。 「入れれない」ってんならともかく、「入ってない」だけなら入れれば済むワケで 最近のOSXにはプリインストールだから使って良いんちゃう サーバ用途だとzshは明示的に入れないと入らないでしょ。稼働中のサーバでは後から入れるにしても難色を示される事も多いですし、上でどなたか書かれてたように、自分に決定権のある環境以外でも使うのなら、zshでスクリプトを書くのは避けるべき。
最近はデフォルトのshellがbashになってたりするけど、昔はbashですら入っていない環境も多くて、/bin/sh で書くように教育されたよ。
年寄り臭くてスマンね >>547
俺も昔おんなじことで悩んでたけど、
>「このスクリプトを使うためにまず zsh 自体をインストールして下さい」
これが通らないような相手のことを考えてスクリプト書いてやるのが馬鹿らしくなって、
以来悩むのはやめたわ。それ自体が仕事だとそうもいかんのだろうけど。 >>551
パッケージでなら用意されてない環境も今では珍しいと思うけど、
最初からインストールされてるかどうかで言えば、入ってない環境なんて
山ほどあるかと。
他の人も書いてるけど、デスクトップ用途ならともかく、サーバ用途なら
sh、csh、bash、tcshぐらいまでしか入ってないとかは普通にあり得る。 csh系は論外とすると、結局無難なのはshかbashだろうか bashがデフォで入ってない環境もあるんで、
無理のない範囲でshにしとくといいよ。 > 年寄り臭くて
いいえ、助言助かりますよ。かつてのbashの位置にようやく追いついたということですね。
先輩方どうもありがとう。
サーバーで使うなら、zsh は諦めるけど
デスクトップでは使ってもいいなと思えてきた。 そうすると気になるのは、fish や Go との差はどうなのかってこと。 必要ならインストールさせればいい、ってスタンス
なら、当然その辺がライバルになってくるけど… まあいいか。スレにみんなにお礼と言ってはナンですが、makefile で zsh を使う方法を考えたので紹介させてください
~ makefile で zsh を使う・Makefile ~
# 設定をまとめた親ディレクトリ.
export ZDOTDIR := $(TMPDIR)/make.$(shell echo $$PPID).zsh
$(ZDOTDIR):
@cd $(@D); mkdir $(@F)
$(ZDOTDIR)/.zshenv: | $(ZDOTDIR)
@exec 1> $@; echo setopt rcquotes
$(ZDOTDIR)/all: $(ZDOTDIR)/.zshenv # マーカーファイル。この行の依存関係に .zshrc などを並べてね.
@touch $@ # 依存関係をまとめたいだけなので、中身はからっぽで.
-include $(ZDOTDIR)/all # このように include することでレシピの実行などでシェルが使われる前に設定ファイル群を作れる. マーカーファイルはない状態から作るのでエラーメッセージはかならず出る。それを消すための先頭のハイフン.
SHELL := /bin/zsh # zsh の設定ファイルは ZDOTDIR 環境変数で渡される.
# なおレシピ外の行での $(shell ...) 関数から呼ばれるシェルは、直前のSHELL設定行より下では作られた ZDOTDIR が有効になった zsh が使える。その行より上ではただの /bin/zsh が使われる.
hoo:
echo 'hoo''bar'
~ makefile で zsh を使う・実行 ~
$ make hoo
echo 'hoo''bar'
hoo'bar zshwiki.orgってまだ落ちてるの?
もしかして閉鎖? fishでshift+tabを押すと補完候補をインクリメンタルに選択出来るんだけど、これに似た機能はzshないかね hoge hoge hoge 〜 hoge
と文字列を任意個展開するスマートな方法ないですかね?
for文使えとかそういうのはなしでお願いします
マニュアルのExpansionの章をくまなく読めばわかるのかもだけど echo $(yes hoge | head -10) あ、repeatコマンドもなしでお願いします
{hoge(n)} みたいに短くスマートにやる方法が知りたい forもwhileもrepeatも使ってないからセーフ >>568
あ、bashでこんな手があるんですね
yesって何に使うのだろうと思ってた
ただ、天下のzshですからもっとzshらしい方法があるはず zsh本来の力の10%も使いこなしてないけど、せめてExpansion系は使いこなしたいわ
>>566
fishよく知らないんだけどインクリメンタル補完って何?
もしかしてサジェスト系? ぼうやーってわしもちふつうだけど、まーおこめのほうがいいんだけど
エラーの原因が分からない?
まず確認しよう!
《書き込めない時の早見表》
《掲示板へ戻る》
《スレッド一覧へ戻る》
《スレッドへ戻る》
もしかしてアクセス規制ですか?
お使いのプロバイダさんが、原因となった人に対応するまで規制は続きます。
個別の対応・進展については、プロバイダさんへお尋ねください。
その他、5chちゃんねるについては、 初心者の質問 批判要望 運用情報 運用臨時 などへどうぞ。
あーめんどくさいなー、びんぼうだしさいごだし、ぼうそういこかなあれはあるか わしかわいそーきょうじゅうにじょうものんだし、ああじゅよんのむと、ししょーあるksなきのせいかな [ $i -lt 100000 ] と [[ $i -lt 100000 ]] では後者のほうが速い
Linux上では2.5倍ぐらい後者が速いが、
WSL上では10倍以上の差をつけて後者が速い
他のシェルでも似たような傾向はあるがこれほどの差はない
どうもzshはシステムコール呼びすぎっぽいな [ ] が遅いって言うよりも関数呼び出しが遅い気がするな
while [[ $i -lt 100000 ]]; do を
↓
foo() {
[[ $i -lt 100000 ]]
}
while foo; do
こんな感じに置き換えてみたら、同じように遅くなった
[ ] を使っていた場合、最初から関数呼び出し相当だったということかも ベンチマークで、ループしてevalとそうでない場合の
速度差を調べようと思ったんだが、まさかループの回数判定で
evalと同等の差がでるとはwww
evalもzshだけ遅い。他のシェルはeval使っていても
ほとんど速度は落ちないというのに 俺の知る限り、現在使われてるBourne系シェルの
全てで [ はビルトインになっている setopt forcefloatして(( ))の数値演算すると固定表示で出力される仕様みたい
それはいいんだけど、最後の桁に誤差が混じってちょっと困る
なにかいい方法ないかな
$ echo $(( 1 ))
1.
$ echo $(( .1 ))
0.10000000000000001 ←0.1 ってなってほしい >>588
printf じゃだめかな?
$ printf "%.1f\n" $((.1))
0.1
$ printf "%.2f\n" $((5.1))
5.10 printfで0.999999999999999になったとき
どう表示されるのだろうか 先輩、手の空いてる時に教えていただけませんか?
ssh接続して、サーバー内で
[server:~] $ sudo rm -f `ls -1t /home/user/work/*.mp4 | tail -n+3`
は、おkなのですが、
[local:~]$ ssh hostname “sudo rm -f `ls -1t /home/user/work/*.mp4 | tail -n+3`”
は、
zsh: no matches found: /home/user/work*.mp4
で、うまくいきません。
サーバー はbash しか入ってないです。
これってどうしたらうまくいくがアドバイスいただけませんでしょうか。
rmするのにsudoしてるのは、docker run -v してるディレクトリで
コンテナが吐き出すファイルだからです。 >>591
\*.mp4 みたいにエスケープするとどうなる? レスありがとうです!
エスケープ試してみたのですが、
zsh: no matches found: /home/user/work*.mp4
で結果は変わらなかったです。 クライアント側のzshが先にワイルドカード展開しようとしてエラーになってるのかな
ダブルクオートをシングルクオートにするのはどうか
lsコマンドを囲んだ元のシングルクオートはエスケープするか$()で置き換えるか ls を囲んでるの、シングルクオートじゃなくてバッククオートなんだよ。
だから ssh を呼び出す前にクライアント側のシェルで展開されて、何もマッチしないから空の文字列になってる。
単純にダブルクオートをシングルクオートに変えるだけでいいと思うよ。 >>594-595
ダブルクオートをシングルにしたらいけました。
天才! ありがとうございます! ワイルドカードの質問ですが
mkdir ~/hoge
touch ~/hoge/fuga
ls ~/hoge/fu*
最後の行のfu*がタブ押しても補完してくれません
~が$HOMEだと補完してくれます
バグですかね? >>597
バグだろうね
自分の環境では補完されるからキーボードかPC捨てて買い換えろ (( a = 0 )) と (( a = それ以外の数値 )) の終了ステータス $? が
それぞれ1と0なんどけど仕様?(( a = 0.0 )) とかにしても1。
変数に設定された値自体が終了ステータスに影響するっておかしくない?
エラーがあると困るシェルスクリプトでは最初に set -e するようにしてるんだが
これじゃ (( )) で数値演算したいときに超困る >>599
ちょっと調べてみた
まずbashでhelp letを見てみると
Exit Status:
If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
とあるので((...))は中身が0に評価されたときのみ1を返す
じゃあa=0とa=1(これはassignment)がどんな値に評価されるのか?だけど
POSIXを見ると$((...))の中身はCのルールに従って評価されると書いてある
((...))もPOSIXには無いけど同じルールに従うはず
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tag_17_01_02_01
で、Cだとassignmentはassignされた値を返すので
((a=0))は0、((a=1))は1を返すということになる
一言で言うと(( ... ))の中はCのルールが適用されるからということかな
set -eの回避策は((a=0, ..., a>100))とか、: $((a=0))とか、if文の中に押し込むとか色々ある 間違えた修正
誤 ((a=0))は0、((a=1))は1を返すということになる
正 ((a=0))は1、((a=1))は0を返すということになる >>600,601
調べてくれてありがとう。Linux歴15年以上あるのに今頃知りましたよ
: $(( 〜 )) のスタイルにするしかないかー。面倒だ
ちなみにこんなwhile処理で発覚した。致命的なミスをする前に気づけてよかった
set -e
(( x = xmin ))
while : ; do
〜処理〜
(( x += dx ))
(( x > xmax )) && break
done
変数は全部浮動小数ね gitで
M ../a1.txt
M ../a2.txt
こんな風に親ディレクトリに変更ファイルがあるとき
git add <Tab>
で候補だしてくれないじゃん。
git add ../<Tab>
なら出るんだけど。これ出るようにできないかね? >>602
このスレは始めてきたので今更だが
普通は
x=$((xmin))
x=$((x+dx))
[ "$x" -gt "$xmax" ]
とかやろ? せっかくzsh使ってんのに-gtだの-leだのまどろっこしい書き方できるかよ ~/.zsh_historyファイルを読んで、コマンド実行の傾向を分析するkibanaのdashboardを作りました。
dockerで作らているので、非常に簡単に始められます。
もし良かったら使ってみてください。
https://github.com/codequokka/shell-history-analyzer lsのソートについて質問
ファイル名先頭の_が無視されるのか
hoge1 _hoge2 hoge3
となるのだけど
_hoge2 hoge1 hoge3
とするにはどうしたらいいの? >>609
zshの問題じゃなかったんだ
失礼しました
ありかとう 新しい macOS のデフォルトシェルが zsh になるってよ! bashですら重いのに、更に重いzshにするのか・・・
誰が喜ぶんだ? Macのシェルなんて素人さんしか使わねぇよ
WSLと同じ
品質なんかどうでも良い タブ補完で例えば、
cp oo/oo kk/kk の oo/から保管して
ppppを入力する場合、ooとppppの差分の2文字が上書きされるのですが、回避する方法はありますか?
上の場合だと
cp oo/ppppk/kk のような結果になります。 カレントシェルで文法チェックのためにdryrunしたい。
zsh -n $BUFFER で変数 BUFFER をチェックできるけど、
新しくシェルを立ち上げるから setopt がズレてるおそれがあり、
いまのシェルで $BUFFER が実行できることを保証できない。 たとえば ignore_close_braces がオンになっていると
args(){ echo $# } はパースエラーになる。 そもそも dryrunである以上、$BUFFER が実行できることなんて保証できない
setoptを含め、実行時にしかわからない情報に依存するものは
実行しないdryrunでわかるわけがない >>622
なら zsh -n は何の役にたつの?
文法をチェックする… ただしパーザの挙動を変えるsetoptが起こる場合
結果は正しくない。起こるか否かも動的にしか判らないのだから、
静的に保証できるものは何もないのでは。 622はおそらく間違っている。
現在のオプションを参照するカレントシェルで動く文法チェッカがあれば、
$BUFFERの実行を伴わない文法チェックはできると思う。
setopt によるパーザの変更はひとつのコマンド行が終わった後に効くっぽいからだ。
二行のファイル
setopt ignore_close_braces
args(){ echo $# }
をsourceすると失敗するが、一行に結合してインタラクティブシェルから呼ぶと成功する。 >>623
> なら zsh -n は何の役にたつの?
構文チェックであり、実行時チェックではない。 args(){ echo $# }
は ignore_close_braces がオンであろうがオフであろうが
そのオプションとは無関係に正しい文法
だからzsh -nでチェックすると正しい文法として扱われる
args(){ echo $# } という関数定義命令を実行すると、
パースエラーという "実行時エラー" が出る
「パースエラーなんだから、実行時エラーじゃないやい!」なんて理屈は通じない。
evalで変なコードを実行したらパースエラーになるだろ
実行時パースエラーというのものが存在する
dry-runである以上、実行時パースエラーを見つけることは不可能
zsh -nは間違ってる文法を「間違ってる文法」だと保証してくれるが
「正しい文法」だとは保証していない evalがある言語では ソースコードのパースも(一部は)実行時に行われる
dry-run=実行しない以上、実行時にしかわからないエラーを見つけられるわけがない。 ignore_close_braces オンで文法チェックしたいなら、
こうすればいいだけ
zsh -o ignore_close_braces -n >>626
構文チェックだけして実行時パースはどうでもいいって状況があるのか?
ともあれ zsh -n の働きはわかった。構文チェック -> 実行時パース の順で通していくわけだね。
今回の俺の目標は$BUFFERの実行時パースって位置づけか。
>>628
サンクス、現在のコマンドラインの$BUFFERとその時点のオプションを渡せば目標は達成できるぜ。
実行なしでの文法チェックができた。
もちろん$BUFFER内のevalの引数まではチェックしないけど、そこまでは元々期待してない。 いやその理解はおかしい。構文チェックが二段階あるわけではない。
インタラクティブシェルでは実行時パースの単位はコマンド行の実行毎になるというだけ。
そのため$BUFFERのチェックに限っていえば、パースは一回なので、
途中でのパーザ変更は変数中に効果を発揮しない。故にドライランで構文チェックができる。
> args(){ echo $# }
> は ignore_close_braces がオンであろうがオフであろうが
> そのオプションとは無関係に正しい文法
ノー。zsh -o ignore_close_braces -n ... で判定するとエラーになる。zsh -n の機能は単に構文チェックするというだけ。
その例のようにパーサの変更がない区間での構文チェックで役にたつ。
アドバイスにおいて、レスをよく読まずに一般論でドヤ顔したり、相手の思考を妄想して叩くべきではない。 あとはこんなときとかに使えるね。
make(){
zparseopts -D -M -E -A opts -- n -just-print=n -dry-run=n -recon=n
if [[ $opts[(i)-n] ]];then
command make -f =(echo '.SHELLFLAGS := -n -c') "$@"
else
command make "$@"
fi
}
これは make の dryrun をシェルの dryrun に置き換える。スクリプトを表示するだけだったのが、文法もチェックするようになるよ。
$ make -f =(echo 'SHELL = zsh';echo 'hoo:; echo hoo)') -n
echo hoo)
zsh:1: parse error near `)' >>630
> いやその理解はおかしい。構文チェックが二段階あるわけではない。
二段階あるんじゃないよ。
-nによる構文チェックは実行せずに静的な構文チェックを行う。
実行しないから実行したら文法エラーになるようなものを見逃す。
通常の実行時は静的な構文チェックは行わずに、実行しながら構文チェックを行う
二段階あるんじゃなくて、二種類あるんだよ。 んで、話は最初に戻る
そもそも dryrunである以上、$BUFFER が実行できることなんて保証できない
setoptを含め、実行時にしかわからない情報に依存するものは
実行しないdryrunでわかるわけがない ノー。$BUFFER 実行時の構文チェックは一回だから >>635
何いってんの?
$BUFFERに入ってるのはただのファイル名なんだけど?
zsh -n $BUFFER
構文チェックに通ったからと言って、実行したときに構文エラーが出ないとは限らない
なぜなら、zsh -nは実行したときの構文チェックとは別物だから。 >>636
いや、man zshzle に書いてあるが zsh の変数 $BUFFER は
エディットバッファの中身を格納している。この値は zle のウィジェットから取得できるんだ。
コマンドラインに例えば echo hoo と入力して実行すると BUFFER='echo hoo' になる。
ウィジェットは自作もできて、好きなキーに bindkey 命令で紐づけて呼べる。
読み返して気付いたんだが、620 は書き間違いで
zsh -n -c $BUFFER
が正しい。
zsh スレだから当然BUFFERくらい知ってるよなと思っていて、会話が繋がっていったので疑いもしなかったんだが
これは完全に俺が悪いです。ごめんなさい。 source ~/.zshrc を打とうとして source ~/.zsh_history を実行してしまった悲劇が話題になってた
これどう対策する? https://qiita.com/stilo/items/90f6c6e308c85a4a9460
~/.zshrc を実行するつもりがタブ補完などをスリップしてしまい .zsh_history を実行していまう。
するとヒストリファイル($HISTFILE == .zsh_history)に書かれた過去に実行したコマンドが、順番に source コマンドによって読み込まれて実行される。
記事で紹介されている事故では途中で止められる機会があったから良いものの、運が悪ければ不可逆的・破壊的コマンドが走り重要な情報を含んでるかもしれない現環境がズタズタになる。 ヒストリ先頭に予め終了命令を入れておくという技をtwitterでみた。
手作業だと忘れそうなので、.zshrc にこういうのを書いておけばいいかな。
< $HISTFILE | { mv $HISTFILE{,.bak}; sed '1{/return 1/!i\
echo '"'"'Cannot source `'$HISTFILE'`, Abort.'"'"' >&2;return 1
;}' > $HISTFILE ;} && rm $HISTFILE.bak >>640
リンク先読んでないけど、それコマンド確認しないでEnter押しちゃ何だってトラブルの元だよね
補完offにしとくか、HISTSIZEを2-3ぐらいにしとけば
設定ファイル編集した後に読み込むならsource !$<tab>でもいいんだし