この古い投稿にはコメントできません。
しかし、そのコメントが私にぴったり必要なようで、良い形で新しい投稿を始めました。
jheadでgrepとSEDを介してコードが何をしているのか理解します。
for i in *.JPG; do
j=`jhead "$i" | grep date | sed 's/^File date[^:]\+: \(.\+\)$/\1/'`.jpg
echo mv -i "$i" "$j"
done
私は非常に似た結果が欲しいが、日付を少し変更したいと思います。名前の変更/出力:yyyymmdd-hhmmssがSED正規表現を把握(翻訳)できません。頑張った
sed 's/^File date[^:]\+: \(\d{4}\):\(\d\d\):\(\d\d\) \(\d\d\):\(\d\d\):\(\d\d\)$/\1\2\3-\4\5\6/'
しかし、私が得るものは
File date : yyyy:mm:yy hh:mm:ss
私は本当にSEDとそれを動作させる正規表現を学ぶことに興味があり、SEDがストリーム編集に非常に強力であることに気づきました。私はこの部分を特に理解していません。 [^:] $がEOLを意味するように、キャレットは時々BOLを意味すると思いました...しかし、この記事を投稿しようとし、他のSED投稿を見ながら「^」ということを(再び?)知ることになりました。おそらく「not」を意味するので、[^:]は「match NOT:」を意味します。しかし:
とにかく私は迷子になった。
ベストアンサー1
AFAICT、日付文字列のスペースを文字に変更したいと思いますか-
?
これは実際には非常に簡単です。しかし、まず、このシェルスクリプトにはいくつかの問題があります。まず、$(
コマンドの代わりにバックティックを使用します)
。第二に、不必要にgrepを使用します(sedはここでgrepが実行することを可能にします)。第三に、実行したい正規表現の検索と置換は、1つのステップよりも2つのステップで行うのが簡単です(最初の行の「ファイルの日付」部分を削除してから、残りの日付文字列を変更します)。
拡張スクリプトのバージョンは次のとおりです。
for i in *.JPG; do
j=$(jhead "$i" | sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p}').jpg
echo mv -i "$i" "$j"
done
英語:jhead
コマンドの出力はsedにパイプされます。 sed オプションは、-n
(print) ステートメントを介して指示しない限り、sed に行を印刷しないように指示します。p
この-E
オプションは、基本正規表現(BRE)の代わりに拡張正規表現(ERE)を使用するように指示します。これは、主に修飾子を使用して+
1つ以上のスペースと一致させることができます。
sed スクリプト自体は、まず、行が「ファイルの日付」で始まるかどうかを確認します。その場合、sedコマンドブロック(つまり、{
sumで囲まれた2つ以上のコマンド}
)を実行します。
ブロックの最初のコマンドは、行から「ファイル日付」を削除し、1つ以上のスペース、コロン、1つ以上のスペースを削除します。これにより、日付のみを含む行が作成されます。
2番目のコマンドは、最初の(唯一の)空白文字をダッシュに変更します-
。p
コマンドの最後には、s///
sedに変更された行を印刷するように指示することがあります。
実行例:
$ ls -l *.JPG
-rw-r--r-- 1 cas cas 1110176 Oct 20 14:04 abc.JPG
-rw-r--r-- 1 cas cas 1132711 Oct 20 14:04 def.JPG
-rw-r--r-- 1 cas cas 1061121 Oct 20 14:04 ghi.JPG
$ for i in *.JPG; do
j="$(jhead "$i" |sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p }').jpg"
echo mv -i "$i" "$j"
done
mv -i abc.JPG 2021:10:20-14:04:08.jpg
mv -i def.JPG 2021:10:20-14:04:09.jpg
mv -i ghi.JPG 2021:10:20-14:04:10.jpg
しかし、このスクリプトは特に安全ではありません。たとえば、2つの異なるjpegファイルがまったく同じタイムスタンプを持つことができるという事実は考慮しません。
次のようなものは完璧とは離れていますが、より安全またはより良いでしょう。
for i in *.JPG; do
j="$(jhead "$i" | sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p }')"
c=1
while [ -e "$j-$c.jpg" ] ; do
let c+=1
done
j="$j-$c"
mv -iv "$i" "$j.jpg"
done
(注:このバージョンは実際にファイル名を変更します。これは単なる作業ではありません。echo
これを行わないと、カウンタ変数をいつ増やすべきかわからないため、テストに必要です。$c
)
出力例:
renamed 'abc.JPG' -> '2021:10:20-14:04:08-1.jpg'
renamed 'def.JPG' -> '2021:10:20-14:04:08-2.jpg'
renamed 'ghi.JPG' -> '2021:10:20-14:04:08-3.jpg'
ただし、同じタイムスタンプを持つ9つ以上のjpegファイルがある場合は、それを使用してカウンタがprintf
2桁または3桁でゼロで埋められていることを確認できます。例えば
for i in *.JPG; do
j="$(jhead "$i" | sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p }')"
c=1
while [ -e "$(printf "%s-%03i.jpg" "$j" "$c")" ] ; do
let c+=1
done
j="$(printf "%s-%03i.jpg" "$j" "$c")"
mv -iv "$i" "$j"
done
renamed 'abc.JPG' -> '2021:10:20-14:04:08-001.jpg'
renamed 'def.JPG' -> '2021:10:20-14:04:08-002.jpg'
renamed 'ghi.JPG' -> '2021:10:20-14:04:08-003.jpg'
RE:カラットに関する質問です^
。
角かっこ式の外側では、行開始アンカーです。たとえば、^File date
「ファイルの日付」と一致します。ただ行の先頭に。
角かっこ式内では、式の意味を否定/反転します。たとえば、[A-Z]
AからZまでのすべての文字と一致することは、[^A-Z]
下のすべての文字と一致します。いいえAとZの間。