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

■ このスレッドは過去ログ倉庫に格納されています
2019/10/25(金) 00:08:45.53ID:6btPTvif
シェルスクリプトに関する総合スレッドです。

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

シェルスクリプト総合 その31
https://mevius.5ch.net/test/read.cgi/tech/1565446670/
2019/10/28(月) 00:25:54.20ID:IRy7CIwD
クォートと中なら、平気、なの
2019/10/28(月) 00:28:19.46ID:XocDEeOH
この程度でいちいちbash依存しないでほしい

set -- 201909 201910

for var in $@
2019/10/28(月) 00:34:13.46ID:UoBv9hmi
for loop の場合、デフォルトでは "$@" が対象になるので

for var;do ... ;done

と書ける
2019/10/28(月) 00:48:08.79ID:h0m+PRW8
>>27
クォートしても同じでした。
ls: /home/app/201909/*.log: No such file or directory

>>28
リモート側が
/dev/tty を読み込むために開けませんでした: そのようなデバイスやアドレスはありません
を返してきました。

>>30
ハゲろ!
2019/10/28(月) 00:49:49.60ID:+rzOrIi/
>>26
ssh host 'rm -f $(tail -n+2 $(ls -1t /home/app/'"${var}"'/*.log))'

ってやればいいと思うけど
>>28の人が書いたようにパイプ使ったほうが読みやすい
2019/10/28(月) 00:50:45.01ID:UoBv9hmi
$HOME/.ssh/config に RequestTTY とか書いてない?
2019/10/28(月) 01:18:31.93ID:h0m+PRW8
考えてくれて、レスをくれてありがとうございます。

>>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を書いてます。

取り急ぎ報告します。エラーについては調べてみます。
2019/10/28(月) 01:42:31.88ID:h0m+PRW8
bash: /bin/rm: 引数リストが長すぎます
についてはしかたないので>>28さんのパイプを使うことにしました。

/dev/tty を読み込むために開けませんでした
についてはsshにtオプションをつけました。

`done' 周辺に構文エラーはこれから調べます。

とりあえず当初の目的は達成できました。
みんな親切にありがとうございます。
2019/10/28(月) 13:32:08.60ID:S2HNyEoD
curl ja.wttr.in/tokyo
curl cheat.sh/ls
これ以外に端末で使える便利サイトってある?
2019/10/28(月) 13:35:16.78ID:tEsfLTI+
宣伝おつ
39デフォルトの名無しさん
垢版 |
2019/10/29(火) 09:50:33.80ID:zCzSjgo7
sshを複数回動かすよりも一回で全部やらせちゃった方が効率良いような気がするんだ
2019/10/29(火) 11:14:16.19ID:2AEjd6SF
なにそれ、よさそう。
でもわたしの頭ではどうしたらよいものやら。。
41デフォルトの名無しさん
垢版 |
2019/10/29(火) 12:20:30.44ID:zCzSjgo7
forのループごとsshで引き渡せばいいじゃん。1行の長いシェルスクリプトってことね。
2019/10/29(火) 13:55:53.48ID:2AEjd6SF
まだ帰宅していないので考えただけですが、
ls | tail | rm したいディレクトリが11個あって、
ディレクトリのpwdは/home/'"$var"'/'"$i"'/ みたいに2箇所変数にしてます。
それをssh1行でループを送れるバエた方法があるますか?
2019/10/29(火) 13:59:15.42ID:2AEjd6SF
たしかにsshのループの時にいちいち
Connection to xxx.xxx.xxx.xxx closed
が出てうざかったんですよね。
2019/10/29(火) 14:00:01.92ID:gns1i7FP
ヒアドキュメントにすればいいんじゃない

#!/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
2019/10/29(火) 14:19:01.08ID:gns1i7FP
と思ったけど、リモートホストのどこかにスクリプトファイルを置いて

ssh host /path/to/script

とかやればいいんじゃないかな

> たしかにsshのループの時にいちいち
> Connection to xxx.xxx.xxx.xxx closed
> が出てうざかったんですよね。

なんでこのメッセージが表示されるんだろう…やっぱり pseudo tty を
使ってるよね
2019/10/29(火) 14:32:50.27ID:CowX2GWO
CI/CD で使う、Task Runner みたいな方が良いかも

Ruby なら、Rake を使った、Capistrano とか、
Thor とか
2019/10/29(火) 14:37:21.30ID:g8zM1lJr
rubyはけっこうです
2019/10/29(火) 15:00:21.96ID:2AEjd6SF
> ヒアドキュメント
> リモートホストのどこかにスクリプト
なるほど!それならわたしでも理解できます!

> 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が出ます。
49デフォルトの名無しさん
垢版 |
2019/10/29(火) 15:57:57.38ID:zCzSjgo7
sshで接続する先のサーバに予めシェルスクリプト送り込んでおいてsshで実行だけするという手もあるな。
あまりにも長くて複雑な場合はその方が楽だと思う。

ただし、送り込んでから実行するまでの間に何者かによって別のファイルに置き換えられてしまったら終わりなのでその心配のない環境でしかできない。
50デフォルトの名無しさん
垢版 |
2019/10/29(火) 15:59:43.78ID:zCzSjgo7
うう。リロードし忘れて書いたら既に同じようなのが書かれている。orz
2019/10/29(火) 16:01:56.26ID:spBBwL/I
やり方は忘れたが、ローカルでgzにしたものをワンライナーで
送ってリモートに保存せずに実行っていうのをやったことがある気がする
かもしれないけど、保存していたかもしれない
5246
垢版 |
2019/10/30(水) 15:36:46.01ID:p2ffZ2o0
環境構築のChef は、サーバーに、Ruby をインストールする。
そこで、サーバーに、Ruby Script を転送して、Rubyで実行する

一方、Ansible は、サーバーに、Python をインストールしない

他にも、Capistrano, Terraform などもある
2019/10/30(水) 18:02:20.30ID:ssr4q2PY
>>52
きたーーー!!!
2019/10/31(木) 17:56:20.75ID:pBbgzdOe
cshで書いたスクリプトの途中でキーから入力をしたいんですが
なんという命令で実現できますか?
2019/10/31(木) 18:01:50.06ID:wR8wpXdO
set key_input = $<
2019/10/31(木) 19:36:28.51ID:pBbgzdOe
>>55
サンクス(´・ω・`)
2019/11/06(水) 17:06:15.24ID:4kXKpMLv
aliasってxargsじゃ使えないけど使えたらまずいんだろうか
関数ならexportすればできるけどさ
58デフォルトの名無しさん
垢版 |
2019/11/06(水) 19:12:11.78ID:wTTuQQRz
>>57
まずいとかいうわけじゃなくて、xargsは外部コマンドだよ。
例えば、俺がC言語であるプログラムを作ったとする。
俺のプログラムから、親プロセス(シェル)がなにかもわからないのに、
そのシェルで定義したメモリ内部のものを呼び出せるわけがない
59デフォルトの名無しさん
垢版 |
2019/11/06(水) 19:12:36.64ID:wTTuQQRz
関数も無理やろ?
2019/11/06(水) 19:20:58.71ID:wTTuQQRz
たたbashに関数をexportできる機能があるってのは不思議なんだよなw

まあなんか変なことしてるんだろう。で気にしてなかったけどさ、
少し試してみたら、bashからbashを起動したときには使えるが、
zshだと使えないし、bash→dash→bashの流れでも使えない。
どういう仕組なんだろう?
2019/11/06(水) 19:34:34.77ID:OvjaMqE0
echo 'Hello World' | xargs -I@ bash -c $'shopt -s expand_aliases;alias p="echo";\n p @'
2019/11/07(木) 00:18:43.96ID:dfqCliYv
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で見た
2019/11/07(木) 08:59:49.28ID:C0Y8MuYI
macては動かないのでwindows使ってくださいみたいな暴論
2019/11/07(木) 11:05:05.20ID:cfhO2vSD
>>60
export -f は環境変数に
BASH_FUNC_関数名%%=関数を文字列
を設定してるだけだからじゃね。bashは起動時に環境変数にそゆのがあったら関数とし展開するから使える、その他はそんな環境変数知らんから単なる環境変数のままな感じな
dashは起動すると、その環境変数が引き継がれないからそこで断ち切られる感じかな
関数にしろaliasにしろサブプロセスに引き継ぐという考え自体がイレギュラーな感じだな
2019/11/07(木) 11:11:30.53ID:sEmiRyTj
>>64
やっぱり環境変数経由なのか?
でもちゃんと確認したんだけどなw

まさかbash以外の外部コマンドを実行するときに削除してるとか?
そしてbashの中からexport -pとかしたときは省いてるとか?
2019/11/07(木) 11:19:16.71ID:cfhO2vSD
>>65
bash -> zsh -> bash
で、bashでは関数になってるけど。zshでも環境変数には存在する
環境変数の引き継ぎってどうなってたかなあ
2019/11/07(木) 11:26:10.68ID:mwfKyddL
なんかもろにそれっぽいのがあった。dashは一般的でないような名前のは削除するらしい
https://unix.stackexchange.com/questions/498905/why-is-my-bash-func-foobar-environment-variable-unset-in-shell-subprocesses
2019/11/07(木) 11:52:29.35ID:sEmiRyTj
ようやく見れたw
envで見れるね。export使ってた。
2019/11/07(木) 11:53:35.24ID:sEmiRyTj
この変数使えば、なにか面白いことできそう。
ってか、xargsの引数にできないか?
2019/11/07(木) 11:54:11.02ID:sEmiRyTj
bashを介せば
2019/11/08(金) 00:07:00.88ID:jWGBsuvq
alias xargs='xargs '
echo *txt | xargs ll
.basurcの登録分はこれでもいける
2019/11/14(木) 12:41:11.56ID:RaS+/sOM
uucpとかって今時どういう活用法あるかな?
2019/11/14(木) 12:59:55.09ID:GaAZ8ORG
TrailBlazer でも手に入れたのか
74デフォルトの名無しさん
垢版 |
2019/11/27(水) 15:42:28.61ID:JZevxkSS
kill とtrapでソフトタイマ作ってみた。需要あるかな
2019/11/27(水) 16:34:50.24ID:KOWJoLHR
sleepと何が違うん?
76デフォルトの名無しさん
垢版 |
2019/11/27(水) 18:43:12.26ID:9SXmP3sk
SECONDSとの比較だからずれの蓄積がない。
平行処理が出来る。
2019/11/27(水) 18:48:52.87ID:KOWJoLHR
ずれの蓄積に関しては、sleepでも補正していけばなんとかなるので。
並行処理はまあそうだね。需要あるんじゃない?
コード見てなにかに使えそうなら使うかも
どこまで作り込んでるのかしらないが
78デフォルトの名無しさん
垢版 |
2019/11/28(木) 06:15:51.80ID:f/6vs/+B
シグナル発生をバックグランドで動かしシェルスクリプトのプロセスに送るのがかなめ。
2019/11/28(木) 07:03:59.17ID:uZo2jF8i
うん。それはわかるw
前に条件を満たすまで無限ループ+タイムアウト機能ってのを実装したことがあるから
結局複雑な割にタイムアウトすることはまず無いので廃止したけどさ
2019/11/28(木) 07:05:43.89ID:uZo2jF8i
もしここに書いたらレビューするかもね
内容が気に入ればだけど
81デフォルトの名無しさん
垢版 |
2019/11/28(木) 08:08:54.32ID:f/6vs/+B
いっぺんにアップできないから小出し。
#! /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 &
82デフォルトの名無しさん
垢版 |
2019/11/28(木) 08:09:31.03ID:f/6vs/+B
for ((aa = 0; aa < MAX_TIMER; aa++)); do
tim_flg[$aa]=0;
tim[$aa]=0;
#echo ${tim_flg[*]}
done;
83デフォルトの名無しさん
垢版 |
2019/11/28(木) 08:09:55.57ID:f/6vs/+B
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
84デフォルトの名無しさん
垢版 |
2019/11/28(木) 08:11:04.34ID:f/6vs/+B
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;
終わり
2019/11/28(木) 08:24:45.92ID:uZo2jF8i
なんか動いてるけど、何やってるのかわからんなw
とりあえずCTRL+Cで停止しなかった。
86デフォルトの名無しさん
垢版 |
2019/11/28(木) 08:29:37.54ID:f/6vs/+B
動作を確認するためタイマーのカウントとセットを繰り返しています。
終了するためにはSIGKILLを与えてください。
2019/11/28(木) 08:30:36.19ID:uZo2jF8i
しばし読んでみたけど、やっぱりわからんw

これ指定したn秒ごとにシグナル送るんじゃないのか?
tim配列とかtim_flgの意味がさっぱりだ
2019/11/28(木) 08:41:39.82ID:uZo2jF8i
簡単な所から。まずシグナルはSIGはいらんぞ。
bash限定ならそれでもいいがPOSIX的には無いほうが正しい。
INTはCTRL-Cなので、USR1またはUSR2、もしくはSIGHUPとかの方が良い。
セミコロンはC言語じゃないんだから行を継続しないときにはつけないのが一般的
89デフォルトの名無しさん
垢版 |
2019/11/28(木) 08:42:09.42ID:f/6vs/+B
各タイマが0になったらなんかをちょっとやり、またタイマをセットするというプログラムです

tim配列はタイマ本体です。tim_flg配列はタイマ使用/不使用のフラグです。
2019/11/28(木) 08:49:25.10ID:uZo2jF8i
やっと理解したが、これ説明なしに理解するの大変だぞw
本質的じゃないコードが複雑でそっちのほうが多すぎる。
2019/11/28(木) 08:51:32.36ID:uZo2jF8i
tim_flgの意味がないな。いや意図は想像できる。(というか>>89に書いてあるか)
サンプルとしてはノイズにしかなってないので理解ができない。
2019/11/28(木) 21:14:01.96ID:uBUVzLWV
宿題の添削をしてやるとか親切たなw
2019/11/28(木) 21:36:47.47ID:asJppHFe
目的は、bash依存すんな。って言うことだったんだがなw
流石にbash依存してる部分が、本質的じゃない所ばかりだとやる気が。
バッサリ削ったら簡単に、bash依存なくせるんでどうしようかなと思いながらレス待ちw
2019/11/28(木) 23:49:59.71ID:RaRUIeaw
bash依存しまくりで
https://wandbox.org/permlink/EHSiHk726Bn4qvVO
95デフォルトの名無しさん
垢版 |
2019/11/29(金) 00:53:33.34ID:Fh79+8D6
あんまりソフトタイマに有用性を感じてもらえないようで残念でした。
2019/11/29(金) 01:09:45.97ID:IIqk2+5U
timeoutでやっつけ
2019/11/29(金) 02:19:44.34ID:XcyRQJ1W
>>95
タイマに有用性がないんじゃなくて
君が作ったスクリプトに有用性がなかったんだよ
2019/11/29(金) 04:30:20.91ID:9RHOSbKH
>>94
めんどくせーから、もうそれでいいやw

その程度でbash依存するな
https://wandbox.org/permlink/Uh4eQX682YzoK8rn
2019/11/29(金) 05:10:07.47ID:hA38q2SN
おれおれかよ
100デフォルトの名無しさん
垢版 |
2019/11/30(土) 00:04:41.28ID:FMRNVBPU
Wgetであるサイトの特定のディレクトリ配下の特定のファイルを
ダウンロードしたくて下記のコマンドを書いてもルートのindex.html
しかダウンロードしてくれません。

これは何がまずいのでしょうか?

wget -r -A Download拡張子 -I /Downloadディレクトリ URL
2019/11/30(土) 00:53:41.92ID:KUL76oc2
オプションに -e robots=off -U mozilla でも付けてみたら上手く行くかも
2019/11/30(土) 00:54:25.61ID:czFcPKLy
碌に調べずの返答でアレなんだが多分訪問先のサイトがファイル一覧
を返すのを禁止してる(apache httpd だと Indexes オプションが有効
になってない)からだと思う
103デフォルトの名無しさん
垢版 |
2019/11/30(土) 13:20:31.41ID:f33nsdyy
リファラの偽装が必要かも。知らんけど
2019/11/30(土) 16:49:40.30ID:mvBIEviw
googleはbashがデフォルト
2019/12/01(日) 11:47:31.42ID:0pH8jk7+
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
106デフォルトの名無しさん
垢版 |
2019/12/01(日) 19:22:22.28ID:IoGKXgrY
>>91
tim_flgをゴミ扱いしたこいつがソフトタイマを理解していない。
2019/12/01(日) 19:49:41.33ID:YWi4MX0G
このサンプルでは1固定なんだからゴミやろ
2019/12/02(月) 22:02:29.21ID:9nn8K+iP
親ディレクトリ
-子ディレ クトリ(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がなんやらと警告が出てきます
2019/12/02(月) 22:13:56.47ID:cDa5fVnx
そういう用途なら、forとかlsとか使わないでfind使え
2019/12/02(月) 22:15:41.19ID:cDa5fVnx
いきなりstatがでるような事はやめて、
echo mv なんとか かんとか で実行命令を表示するようにしろ
怖すぎるわ。それやればなんとかなるだろ
2019/12/02(月) 22:19:56.11ID:agtAae1a
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
2019/12/02(月) 22:46:09.47ID:RT0MauQR
find . -name '*[ ()]*' -print | sort -r | while read item; do
mv "$item" "${item%/*}/$(echo "${item##*/}" | tr ' ()' '_')"
done
113デフォルトの名無しさん
垢版 |
2019/12/03(火) 07:24:55.79ID:v9g/lO5M
Ruby で作った。
コードは次のレスに書く

DryRun を使ったので実際には、変更されない

ファイル/ディレクトリは、同時に変更すると、バグるかも知れないので、別々に変更する。
また「子ディレクトリ(1)/孫ディレクトリ(1)」のように、2か所以上同時に変更すると、バグるかも知れない

こんな複雑なものを、シェルスクリプトで書くのは超危険!

特に移動は、dest が存在するときは移動になり、
存在しないときは変更になるという、極めて難しい場合分けが必要で、

処理の途中でエラーになると、エラーまでの処理が確定してしまうから、中途半端で巻き戻せないから、
必ず、親ディレクトリ以下のバックアップを取っておく!
114113
垢版 |
2019/12/03(火) 07:25:55.85ID:v9g/lO5M
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 )
2019/12/03(火) 08:29:02.93ID:ujGDA/f+
なんかかえってめんどくさいことしてんな。perlでめんどくさく書きたいだけ?
2019/12/03(火) 08:29:47.31ID:ujGDA/f+
perlではなくrubyか。しつれい
117113
垢版 |
2019/12/03(火) 09:46:02.07ID:v9g/lO5M
mv を作った奴は、頭おかしいw

dest が存在するときは移動になり、
存在しないときは名前の変更になるという、極めて難しい場合分けが必要だから

漏れらが欲しいのは、
rename だけする関数と、移動するだけの関数の、2つに分かれている関数

それが分かれていないから、自分で処理を分けて、
かなりチェックしないと、バグってしまう
2019/12/03(火) 12:17:58.24ID:5ZiHQIvd
つまり自分に都合が悪い仕様=バグ
2019/12/03(火) 12:28:33.61ID:Uh1tIUQA
一括リネームってたいてい複雑になるから
GUIツールを使ったほうが良いと思うんだよね

Windows 10版のPowerToysにリネーム機能が追加
https://pc.watch.impress.co.jp/docs/news/1215602.html
2019/12/03(火) 18:09:42.76ID:+zVWCKlo
>>112
Fix(IFS文字が頭と末尾にある場合。dirname,basenameにしたのは気分)&Variation
find . -name '*[ ()]*' -print | sort -r | (IFS=''; while read item; do
mv "$item" "$(dirname "$item")/$(basename "$item" | tr ' ()' '_')"
done)


find . -name '*[ ()]*' -print | sort -r | (IFS=''; while read item; do
dir="$(dirname "$item")"; newname="$(basename "$item" | tr ' ()' '_')"; newpath="$dir/$newname"
[ ! -e "$newpath" ] && mv "$item" "$newpath" || echo "can't rename $item, exists $newname" >&2
done
# can't rename $item 〜 メッセージは単なる目安


find . -name '*[ ()]*' -print | sort -r | (IFS=''; while read item; do
dir="${item%/*}"; newname="$(tr ' ()' '_' <<< ${item##*/})"

[ -e "$dir/$newname" ] && {
name="${newname%.*}_"
ext="${newname#*.}"; [ "$ext" = "$newname" ] && ext='' || ext=".$ext"
while [ -e "$dir/$name$ext" ]; do
name+='_'
done
newname="$name$ext"
}

mv "$item" "$dir/$newname"
done)
2019/12/03(火) 18:14:03.14ID:+zVWCKlo
>>120
誤 ext="${newname#*.}"
正 ext="${newname##*.}"
2019/12/03(火) 18:30:56.19ID:HnkJN8FN
>>111
rename自体がperlだしちゃんと試行もあるけど
2019/12/03(火) 19:27:45.48ID:mUaHu9IR
>>122
perl ワンライナーより
dry run のスイッチと
どのように変更させるかに集中し
出力確認などの余計なことは共通する定型処理だから
コードにまとめたほうが使いやすい
2019/12/03(火) 19:44:49.63ID:R2wB6lmg
Linuxディストリによっては標準で入っている、perlスクリプトで作られたrenameコマンドのことだろ
2019/12/03(火) 20:48:36.39ID:jDo5c24e
renameは標準で入ってないとはいえ
テスト無しの自作コードでやるような処理じゃないやろ
find -depth -exec rename -nでdry-runしてから-n消せばいい
2019/12/03(火) 21:32:10.96ID:yTVXI633
話のネタから外れて何を主張したいのだか
2019/12/03(火) 22:25:15.93ID:yTVXI633
dry-runって言っても結局ひとつをrename/mvするその時点での状態でしか判断してないし、mvコマンドの前にecho付けるのと何が違うのだか
[ "$1" = "-n" ] && nac=echo || nac=''
$nac mv ...
でスイッチにしたけりゃ同じようにできるだろし
極めて難しいらしいことも結局時点での存在チェックしてるだけで、シェルスクリプトでtestを使うのと何がそうも極めて難しいほど違うのか

>>122
既に存在してたらエラー(オプションによって強行もできる)でもあるよね
The original C<rename> did not check for the existence of target filenames,
so had to be used with care. I hope I've fixed that (Robin Barker).
って、わざわざコメント書くようにな目玉なw
どのバージョンを使ってるのかわからんけど、パッケージによってはものすごいオプション拡張されたのが使われてるねえ
128113
垢版 |
2019/12/03(火) 23:09:51.48ID:v9g/lO5M
Windows10, WSL, Ubuntu 16.04 にも、/usr/bin/rename がある

この手の処理の何がヤバイかと言うと、

例えば、3つ目の処理で、エラーが出ると、
2つ目までは、変更されてしまっているから、
そこから再実行すると、最初から実行していた時と、初期条件が変わっている

データベースと同じで、一部分だけ更新されたような、中途半端な状態になってはいけない(一貫性)。
エラー時には、すべてをロールバックするべき。
または、全体のバックアップを取っておく

すべてを更新するか、すべてをロールバックするのどちらかの状態だけにする
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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