シェルスクリプト総合 その32
■ このスレッドは過去ログ倉庫に格納されています
シェルスクリプトに関する総合スレッドです。 全般 ・荒しは無視しましょう。 ・丁寧な姿勢を心掛けましょう。 ・ネチケット(死語)を意識しましょう。 ・「○○(他の言語)でいいやん」は禁止。他のスレに行ってください。 シェルスクリプト総合 その31 https://mevius.5ch.net/test/read.cgi/tech/1565446670/ >>15 は [ ! $TRUE ] ← こういうコードを書いてますが、 つまりこういうことですよ FLAG=$FALSE if [ $FLAG ]; then echo ここが実行されるwww fi 変数($FLAG)に、0 or 1 を入れてる人は、 こういう書き方をしたいかんのやで if [ $FLAG ]; then if [ ! $FLAG ]; then if [ $FLAG -eq $TRUE ]; then とか if [ $FLAG -ne $TRUE ]; then って書かないといかん if $FLAG ; then 書き方も知らんらしいw >>21 Mikuの回答とやらで混乱しすぎててわろたw ま、普通考えて、変数の内容を実行するのは危険だわな 0: コマンドが見つかりません を確かめようと、WSLで実行したらエラー無く実行されたw /mnt/c/WINDOWS/system32/0 というファイルが有る。 サイズゼロだから問題ないが、なんだこれw ちなみに1はないのでエラーになる >>9 DECのVAX上で動くシェルスクリプトのようなものでコマプロってあったな 先輩からはコマンドプロシジャーの略って聞いたけど 今調べると「DCL および MCR コマンド言語インタプリタ」って言うのっぽい 適当にぐぐって出てきたPDFに載ってるそれらしい用語だけどさ 20年以上前の話だ、なつかしい・・・ 質問スレでこっちでやれってレスもらったのできました。 そのまま同じ書き込みします。 ↓ リモートで最新の1つを残してログを削除したいです。 $ ssh host 'rm -f `ls -1t /home/app/201910/*.log | tail -n+2`' これを複数のディレクトリで実行しようとしたのが、 var1=201909 var2=201910 array=($var1 $var2) for var in ${array[@]} do ssh host rm -f $(tail -n+2 $(ls -1t /home/app/${var}/*.log)) done なのですが、ls -1t /home/app/${var}/*.logがローカルで実行されてしまい ます。(ls: /home/app/201909/*.log: No such file or directory) うまくいくようにアドバイスなどいただけるとうれしいです。 ssh host 'ls -1t /home/app/'${var}'/*.log | tail -n +2 | xargs rm -f' とか この程度でいちいちbash依存しないでほしい set -- 201909 201910 for var in $@ for loop の場合、デフォルトでは "$@" が対象になるので for var;do ... ;done と書ける >>27 クォートしても同じでした。 ls: /home/app/201909/*.log: No such file or directory >>28 リモート側が /dev/tty を読み込むために開けませんでした: そのようなデバイスやアドレスはありません を返してきました。 >>30 ハゲろ! >>26 ssh host 'rm -f $(tail -n+2 $(ls -1t /home/app/'"${var}"'/*.log))' ってやればいいと思うけど >>28 の人が書いたようにパイプ使ったほうが読みやすい $HOME/.ssh/config に RequestTTY とか書いてない? 考えてくれて、レスをくれてありがとうございます。 >>28 >>31 for var;do ssh host 'ls -1t /home/app/'${var}'/*.log | tail -n +2 | xargs rm -f' ;done hoge.sh: 行 38: 予期しないトークン `done' 周辺に構文エラーがあります をリモート側が返しました。 >>33 + ssh host 'rm -f $(tail -n+2 $(ls -1t /home/app/'"${var}"'/*.log))' bash: 警告: command substitution: ignored null byte in input bash: /bin/rm: 引数リストが長すぎます >>34 リモートには~/.ssh/configは無くて、ローカルはUser、HostName、Port、 IdentityFile、ServerAliveIntervalを書いてます。 取り急ぎ報告します。エラーについては調べてみます。 bash: /bin/rm: 引数リストが長すぎます についてはしかたないので>>28 さんのパイプを使うことにしました。 /dev/tty を読み込むために開けませんでした についてはsshにtオプションをつけました。 `done' 周辺に構文エラーはこれから調べます。 とりあえず当初の目的は達成できました。 みんな親切にありがとうございます。 curl ja.wttr.in/tokyo curl cheat.sh/ls これ以外に端末で使える便利サイトってある? sshを複数回動かすよりも一回で全部やらせちゃった方が効率良いような気がするんだ なにそれ、よさそう。 でもわたしの頭ではどうしたらよいものやら。。 forのループごとsshで引き渡せばいいじゃん。1行の長いシェルスクリプトってことね。 まだ帰宅していないので考えただけですが、 ls | tail | rm したいディレクトリが11個あって、 ディレクトリのpwdは/home/'"$var"'/'"$i"'/ みたいに2箇所変数にしてます。 それをssh1行でループを送れるバエた方法があるますか? たしかにsshのループの時にいちいち Connection to xxx.xxx.xxx.xxx closed が出てうざかったんですよね。 ヒアドキュメントにすればいいんじゃない #!/bin/sh cat <<'EOS' | ssh host sh var1=201909 var2=201910 set -- "${var1}" "${var2}" for var do ls -1t /home/app/"${var}"/*.log | tail -n +2 | xargs rm -f done EOS と思ったけど、リモートホストのどこかにスクリプトファイルを置いて ssh host /path/to/script とかやればいいんじゃないかな > たしかにsshのループの時にいちいち > Connection to xxx.xxx.xxx.xxx closed > が出てうざかったんですよね。 なんでこのメッセージが表示されるんだろう…やっぱり pseudo tty を 使ってるよね CI/CD で使う、Task Runner みたいな方が良いかも Ruby なら、Rake を使った、Capistrano とか、 Thor とか > ヒアドキュメント > リモートホストのどこかにスクリプト なるほど!それならわたしでも理解できます! > Connection to xxx.xxx.xxx.xxx closed これは、 ssh host 'ls -1t /home/app/'${var}'/*.log | tail -n +2 | xargs rm -f' としたときに、 /dev/tty を読み込むために開けませんでした: そのようなデバイスやアドレスはありません と言われてしまったので、sshに-tをつけてから出るようになりました。 サーバーのアプリが集めた写真をscpでダウンロード→ →ダウンロードした写真を削除→アプリのログを削除 って流れのスクリプトなのでやたらとConnection to xxx.xxx.xxx.xxx closedが出ます。 sshで接続する先のサーバに予めシェルスクリプト送り込んでおいてsshで実行だけするという手もあるな。 あまりにも長くて複雑な場合はその方が楽だと思う。 ただし、送り込んでから実行するまでの間に何者かによって別のファイルに置き換えられてしまったら終わりなのでその心配のない環境でしかできない。 うう。リロードし忘れて書いたら既に同じようなのが書かれている。orz やり方は忘れたが、ローカルでgzにしたものをワンライナーで 送ってリモートに保存せずに実行っていうのをやったことがある気がする かもしれないけど、保存していたかもしれない 環境構築のChef は、サーバーに、Ruby をインストールする。 そこで、サーバーに、Ruby Script を転送して、Rubyで実行する 一方、Ansible は、サーバーに、Python をインストールしない 他にも、Capistrano, Terraform などもある cshで書いたスクリプトの途中でキーから入力をしたいんですが なんという命令で実現できますか? aliasってxargsじゃ使えないけど使えたらまずいんだろうか 関数ならexportすればできるけどさ >>57 まずいとかいうわけじゃなくて、xargsは外部コマンドだよ。 例えば、俺がC言語であるプログラムを作ったとする。 俺のプログラムから、親プロセス(シェル)がなにかもわからないのに、 そのシェルで定義したメモリ内部のものを呼び出せるわけがない たたbashに関数をexportできる機能があるってのは不思議なんだよなw まあなんか変なことしてるんだろう。で気にしてなかったけどさ、 少し試してみたら、bashからbashを起動したときには使えるが、 zshだと使えないし、bash→dash→bashの流れでも使えない。 どういう仕組なんだろう? echo 'Hello World' | xargs -I@ bash -c $'shopt -s expand_aliases;alias p="echo";\n p @' func(){ echo $@;} export -f func echo foo | xargs func xargs: func: そのようなファイルやディレクトリはありません echo foo | xargs -I@ bash -c 'echo @' foo 関数ならこうだな xargsでaliasはbashだと無理だからtcshでやれってstack overflowで見た macては動かないのでwindows使ってくださいみたいな暴論 >>60 export -f は環境変数に BASH_FUNC_関数名%%=関数を文字列 を設定してるだけだからじゃね。bashは起動時に環境変数にそゆのがあったら関数とし展開するから使える、その他はそんな環境変数知らんから単なる環境変数のままな感じな dashは起動すると、その環境変数が引き継がれないからそこで断ち切られる感じかな 関数にしろaliasにしろサブプロセスに引き継ぐという考え自体がイレギュラーな感じだな >>64 やっぱり環境変数経由なのか? でもちゃんと確認したんだけどなw まさかbash以外の外部コマンドを実行するときに削除してるとか? そしてbashの中からexport -pとかしたときは省いてるとか? >>65 bash -> zsh -> bash で、bashでは関数になってるけど。zshでも環境変数には存在する 環境変数の引き継ぎってどうなってたかなあ ようやく見れたw envで見れるね。export使ってた。 この変数使えば、なにか面白いことできそう。 ってか、xargsの引数にできないか? alias xargs='xargs ' echo *txt | xargs ll .basurcの登録分はこれでもいける kill とtrapでソフトタイマ作ってみた。需要あるかな SECONDSとの比較だからずれの蓄積がない。 平行処理が出来る。 ずれの蓄積に関しては、sleepでも補正していけばなんとかなるので。 並行処理はまあそうだね。需要あるんじゃない? コード見てなにかに使えそうなら使うかも どこまで作り込んでるのかしらないが シグナル発生をバックグランドで動かしシェルスクリプトのプロセスに送るのがかなめ。 うん。それはわかるw 前に条件を満たすまで無限ループ+タイムアウト機能ってのを実装したことがあるから 結局複雑な割にタイムアウトすることはまず無いので廃止したけどさ もしここに書いたらレビューするかもね 内容が気に入ればだけど いっぺんにアップできないから小出し。 #! /bin/bash MAX_TIMER=10; OLD_SECONDS=$SECONDS; while true; do cp_SECONDS=$SECONDS; if [ $cp_SECONDS -ne $OLD_SECONDS ]; then kill -SIGINT $$; OLD_SECONDS=$cp_SECONDS; fi sleep 0.5; done & for ((aa = 0; aa < MAX_TIMER; aa++)); do tim_flg[$aa]=0; tim[$aa]=0; #echo ${tim_flg[*]} done; trap ' for ((aa = 0; aa < MAX_TIMER; aa++)); do if [ ${tim_flg[$aa]} -eq 1 ]; then if [ ${tim[$aa]} -gt 0 ]; then tim[$aa]=$((tim[$aa] - 1)); fi fi done printf "%3d" ${tim[*]}; echo ":" $(date -R); ' SIGINT for((nn=0; nn < 10; nn++)); do tim_flg[$nn]=1; done while true; do for((nn=0; nn < 10; nn++)); do if [ ${tim[$nn]} -eq 0 ]; then tim[$nn]=$((nn + 2)); fi done sleep 0.6 done; 終わり なんか動いてるけど、何やってるのかわからんなw とりあえずCTRL+Cで停止しなかった。 動作を確認するためタイマーのカウントとセットを繰り返しています。 終了するためにはSIGKILLを与えてください。 しばし読んでみたけど、やっぱりわからんw これ指定したn秒ごとにシグナル送るんじゃないのか? tim配列とかtim_flgの意味がさっぱりだ 簡単な所から。まずシグナルはSIGはいらんぞ。 bash限定ならそれでもいいがPOSIX的には無いほうが正しい。 INTはCTRL-Cなので、USR1またはUSR2、もしくはSIGHUPとかの方が良い。 セミコロンはC言語じゃないんだから行を継続しないときにはつけないのが一般的 各タイマが0になったらなんかをちょっとやり、またタイマをセットするというプログラムです tim配列はタイマ本体です。tim_flg配列はタイマ使用/不使用のフラグです。 やっと理解したが、これ説明なしに理解するの大変だぞw 本質的じゃないコードが複雑でそっちのほうが多すぎる。 tim_flgの意味がないな。いや意図は想像できる。(というか>>89 に書いてあるか) サンプルとしてはノイズにしかなってないので理解ができない。 目的は、bash依存すんな。って言うことだったんだがなw 流石にbash依存してる部分が、本質的じゃない所ばかりだとやる気が。 バッサリ削ったら簡単に、bash依存なくせるんでどうしようかなと思いながらレス待ちw あんまりソフトタイマに有用性を感じてもらえないようで残念でした。 >>95 タイマに有用性がないんじゃなくて 君が作ったスクリプトに有用性がなかったんだよ Wgetであるサイトの特定のディレクトリ配下の特定のファイルを ダウンロードしたくて下記のコマンドを書いてもルートのindex.html しかダウンロードしてくれません。 これは何がまずいのでしょうか? wget -r -A Download拡張子 -I /Downloadディレクトリ URL オプションに -e robots=off -U mozilla でも付けてみたら上手く行くかも 碌に調べずの返答でアレなんだが多分訪問先のサイトがファイル一覧 を返すのを禁止してる(apache httpd だと Indexes オプションが有効 になってない)からだと思う bash/zsh依存しまくりで https://wandbox.org/permlink/moif346imXqiuDxD そんなのが仮に必要でも trap 'date -R' USR1 for (( i=1 ; i <= 10 ; i++ )); do ( sleep $i; kill -USR1 $$ ) & done wait でいいだろとしか思わんけどw >>91 tim_flgをゴミ扱いしたこいつがソフトタイマを理解していない。 親ディレクトリ -子ディレ クトリ(1) file(1).txt file ().txt -子デ ィレクトリ(2) file(2) .txt -子ディレクトリ(3) fil e(3).txt ディレクトリとファイル名の半角スペースと半角の()を_で置換したいのですが どうやればいいのでしょうか for dir in $(ls -d */); do for f in ${dir}*; do mv "$f" `echo $f|sed -e 's/[ ()]/_/g'` done done これでディレクトリ名とファイル名はどうにかなったのですが、、 一回目ではディレクトリ名が変換されてしまうのでファイル名が変換されず 対応策として同じコードを2回実行してファイル名も変換しています まず一回目にディレクトリ名を変換するために for dir in $(ls -d */); do mv "$dir" `echo $dir|sed -e 's/[ ()]/_/g'` done をやってみたのですが、statがなんやらと警告が出てきます そういう用途なら、forとかlsとか使わないでfind使え いきなりstatがでるような事はやめて、 echo mv なんとか かんとか で実行命令を表示するようにしろ 怖すぎるわ。それやればなんとかなるだろ rename 関係はperlで試せる dry run 作ってる https://pastebin.com/0uJ462jq touch "file(1).txt"; ~/bin/rename.pl dry 'tr/[()]/_/' *txt file(1).txt => file_1_.txt ~/bin/rename.pl run 'tr/[()]/_/' *txt; ls file_1_.txt find . -name '*[ ()]*' -print | sort -r | while read item; do mv "$item" "${item%/*}/$(echo "${item##*/}" | tr ' ()' '_')" done Ruby で作った。 コードは次のレスに書く DryRun を使ったので実際には、変更されない ファイル/ディレクトリは、同時に変更すると、バグるかも知れないので、別々に変更する。 また「子ディレクトリ(1)/孫ディレクトリ(1)」のように、2か所以上同時に変更すると、バグるかも知れない こんな複雑なものを、シェルスクリプトで書くのは超危険! 特に移動は、dest が存在するときは移動になり、 存在しないときは変更になるという、極めて難しい場合分けが必要で、 処理の途中でエラーになると、エラーまでの処理が確定してしまうから、中途半端で巻き戻せないから、 必ず、親ディレクトリ以下のバックアップを取っておく! require 'fileutils' root_dir = "C:/Users/Owner/Documents/Ruby/test/**/*" # 基準ディレクトリ # 変更前のファイル/ディレクトリを入れる配列 src_files = [ ]; src_dirs = [ ] # 基準ディレクトリ以下のファイル/ディレクトリを取り出して、配列に入れる Dir.glob( root_dir ) do |path| case when File.file?( path ) then src_files.push ( path ) when File.directory?( path ) then src_dirs.push ( path ) else # 処理しない end end def change_paths( src_ary ) # ファイル/ディレクトリ名を変更する src_ary.each do |src_path| dest_path = src_path.tr( " ()", "_" ) # 変換 next if src_path == dest_path # 変換されなかった場合は、処理しない # 変更後の名前のファイル/ディレクトリが、既に存在すれば、エラー msg = "変更後の名前のファイル/ディレクトリが、既に存在します!\n#{ dest_path }" raise msg if File.exist? ( dest_path ) FileUtils::DryRun.move( src_path, dest_path ) end end change_paths( src_dirs ) change_paths( src_files ) なんかかえってめんどくさいことしてんな。perlでめんどくさく書きたいだけ? ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.4 2024/05/19 Walang Kapalit ★ | Donguri System Team 5ちゃんねる