web-dev-qa-db-ja.com

複数のファイルの名前を変更し、途中に日付を追加する

次のように、Solarisで、元の拡張子を保持したまま、名前に現在のタイムスタンプを含めて、フォルダ内のすべてのファイルの名前を変更したいと思います。

test1.txt> test1.date.txt

私はこれを試しましたが、名前の最初の部分を失います:

find * -Prune -type f -name '*.txt' -exec mv {} {}.$(date +'%Y%m%d%H%M').txt \;

何が欠けていますか?

5
_find . -type f -name '*.txt' -exec sh -c '
    now=$( date +%Y%m%d%H%M )
    for pathname do
        mv "$pathname" "${pathname%.txt}.$now.txt"
    done' sh {} +
_

これにより、現在のディレクトリ内またはその下にある通常のファイルのすべてのパス名が検索され、その名前は_.txt_で終わります。これらのバッチの場合、短いシェルスクリプトが呼び出されます。このスクリプトは、最初にタイムスタンプを取得し(効率を上げるために、バッチごとに1回しかありません)、指定されたパス名をループします。

パス名ごとに、最後の_.txt_を削除し(_${pathname%.txt}_を使用)、ドット、タイムスタンプ、および_.txt_を追加することにより、パス名を変更します。

これはSolarisではテストされていませんが、標準のコンポーネントとオプションのみを使用しています。

タイムスタンプを1回だけ計算するには、findを呼び出す前に、

_now=$( date +%Y%m%d%H%M ) \
find ...as before (but without assigning to now)...
_

または

_env now="$( date +%Y%m%d%H%M )" \
find ...as before (but without assigning to now)...
_

(上記の2つのコマンドの行の継続に注意してください)

ファイルがsingleディレクトリにある場合は、ループを実行するだけです。

_now=$( date +%Y%m%d%H%M )
for pathname in ./*.txt; do
    mv "$pathname" "${pathname%.txt}.$now.txt"
done
_

これは、パターン_./*.txt_が、名前を変更するすべての名前に一致すると想定しています。

関連:


あなたの{}.$(date +'%Y%m%d%H%M').txtは移植性がありません。 findの一部の実装で機能する可能性がありますが、_{}_が別の文字列と一緒に出現する場合、_{}_を現在のパス名に展開する実装は必要ありません。

POSIX標準は からの関連テキスト:

_utility_name_または2文字のみを含む引数_{}_は、現在のパス名に置き換えられます。 _utility_name_または引数文字列に2つの文字_{}_が含まれているが、2つの文字_{}_だけではない場合、findがそれらを置き換えるかどうかは実装定義です2文字または変更なしの文字列を使用します

8
Kusalananda

別の方法ですが、solarisとの互換性がよくわかりません...

from=txt
to=$(date +%Y%m%d%H%M).txt
find * -Prune -type f -name "*.$from" -exec sh -c 'mv "$3" "${3%.$1}.$2"' sh "$from" "$to" {} ';'

@Kulasanandaによって与えられた nix.stackexhange リンクから恥知らずに盗まれましたが、shからの呼び出しがsh -c mvの変数を構成する方法が好きです。

甘い。

3
bu5hman