Bash - 入力番号で始まる数字でソートされたファイルの移動/名前の変更

Bash - 入力番号で始まる数字でソートされたファイルの移動/名前の変更

次のファイル番号のリストがあります。

01_file_name.log
01_file_name.txt
02_file_name.log
02_file_name.txt
03_file_name.log
03_file_name.txt
04_file_name.log
04_file_name.txt
05_file_name.log
05_file_name.txt

03*すべてのファイルに04*新しいファイルを挿入したいです。したがって、ワード番号から始めて03すべてのファイルを移動/名前変更し、前の番号を2ずつ増やす必要があります。したがって、リストは次のようになります。

01_file_name.log
01_file_name.txt
02_file_name.log
02_file_name.txt
05_file_name.log
05_file_name.txt
06_file_name.log
06_file_name.txt
07_file_name.log
07_file_name.txt

私は次のことを考えています。 bash script.sh 03 02while03は、$1起動するファイル名の番号と追加する番号です02$2入れ子にしてこれを達成しようとしましたが、ループがワード内の指定された番号のファイルのみを実行するようにfor-loopカウンターを使用する組み合わせを放棄する必要がありました。((++))

答え1

これがあなたが望むものです。一つ:BASHでしか動作しないと思います。 MAXDIGITSオプションなので、3桁以上を使用する必要がある場合を備えています。使用しない場合は、その行を削除してください。

    #!/bin/bash

    BOTTOM=$1
    SHIFT=$2
    MAXDIGITS=0$3
    for filename in $(ls -r *.{txt,log}); do
        PREFIX=${filename%%_*}
        NEWPREFIX=$(expr $PREFIX + $SHIFT)
        if [ $PREFIX -ge $BOTTOM ]; then
            NEWPREFIX=$(printf %${MAXDIGITS}d $NEWPREFIX)
            mv $filename ${NEWPREFIX}_${filename#*_}
        fi
    done

指示:

    ./myscript <BOTTOM> <SHIFT> <MAXDIGITS>
    ### Example:
    ./miscript 03 02 2 #This means "Start at 03_filename.*, shift the prefixes by 2 and use 2 digits to construct the new prefixes".

同じディレクトリに同じ構文(prefix_filename。{txt、log})に従わない他のファイルがある場合は、フィルタリングする必要があります。そして、プレフィックスとファイル名を区別するために "_"を使用したので、それを変更したらコードを修正する必要があります。

答え2

それは価値があるので、これはbash2つのものを含む1つのライナーです。プロセスの交換非常に簡単なawkプロセスです。

$ ls -r -1 *_file_name.{txt,log}    # list initial files in reverse order
05_file_name.log
05_file_name.txt
04_file_name.log
03_file_name.txt
03_file_name.log
03_file_name.txt
02_file_name.log
02_file_name.txt
01_file_name.log
01_file_name.txt

$ source <(awk 'BEGIN{FS="_"} $1>2 {prefix=$1+2; printf ("mv -f %s %0.2d_%s_%s\n",$0,prefix,$2,$3)}' <(ls -r -1 *_file_name.{log,txt}))

$ ls -1 *_file_name.{txt,log}     # list resulting files
01_file_name.log
01_file_name.txt
02_file_name.log
02_file_name.txt
05_file_name.log
05_file_name.txt
06_file_name.log
06_file_name.txt
07_file_name.log
07_file_name.txt

説明する:

上記の行は右から左に読み取るか、少なくとも「理解」します。

  • ls -r -1 *_file_name.{log,txt} 処理するすべてのファイルを1列形式で逆順にリストします。
    ファイルプレフィックス(記号で示す*)に数字以外の文字が含まれていると、予期しない/望ましくない結果が発生する可能性があります。これを防ぐには、この手順で処理するファイルをフィルタリングしてください。

  • <(...)クラフトの交換。ファイル記述子、名前付きパイプと呼ばれる特別な一時ファイルを使用して、以前の結果出力を参照できます。詳しくはman bash端末に投稿してください。

  • awkスクリプト:

    • BEGIN{FS="_"} レコード処理を開始する前に、レコードのフィールド区切り文字を「_」(awkの最初のブロック)に設定してください。
    • awk2番目のブロックの条件$1>2:ファイル名のプレフィックスが2より厳密に大きいレコードのみを処理します。
    • prefix=$1+2awkの「プレフィックス」内部変数を定義します。プレフィックス$1+ 2と数値的に等しくなります。
    • printf("my_format",var1,var2,...)改行で区切られた印刷書式設定コマンド。書式設定には、%0.2d変数「プレフィックス」をawk2桁の数字で印刷し、必要に応じてゼロを埋める操作が含まれます。出力は次のとおりです
      mv -f 05_file_name.log 07_file_name.log
      mv -f 05_file_name.txt 07_file_name.txt
      mv -f 04_file_name.log 06_file_name.log
      mv -f 04_file_name.txt 06_file_name.txt
      mv -f 03_file_name.log 05_file_name.log
      mv -f 03_file_name.txt 05_file_name.txt
  • ソートされた出力を別のファイル(2番目のプロセスの置き換え)として処理し、コマンドを実行するようにしますmv -f ...

なぜ再利用するのか気になったらインバウンドまたはアウトバウンドプロセスの交換(POSIXではありません!)inが有利ですbashこれ例えば。

最終注意事項:

上記のコード行にランタイムパラメータを含め、実行可能なシェルスクリプトにカプセル化するのは簡単です。定義VAR1してVAR2割り当てるプロセスから始めてくださいawk

$ source <(awk -v VAR1=2 -v VAR2=2 'BEGIN{FS="_"} $1>VAR1 {prefix=$1+VAR2; printf ("mv -f %s %0.2d_%s_%s\n",$0,prefix,$2,$3)}' <(ls -r -1 *_file_name.{log,txt}))

実行可能スクリプトからscript.sh

$ cat script.sh
#!/usr/bin/bash
if [ "$#" -eq 2 ] ; then
    source  <(awk -v VAR1=$1 -v VAR2=$2 'BEGIN{FS="_"} $1>VAR1 {prefix=$1+VAR2; printf ("mv -f %s %0.2d_%s_%s\n",$0,prefix,$2,$3)}' 
              <(ls -r -1 *_file_name.{log,txt})
             )
    exit 0
else
    echo "   Usage: script.sh VAR1 VAR2.\n    Abort execution (exit code 1)."
    exit 1
fi

ここではVAR1VAR2OPで定義された意味があります。本番環境でこのスクリプトを使用する必要がある場合は、入力ファイルと変数の値が常に予想されることを確認するために、多くのスキャンと安全装置を追加することをお勧めします。

for@MarceloCastroのスクリプトは素晴らしいですが、可能であれば避ける傾向があるループに基づいています。forループは遅い傾向があります。ループを操作すると、これがわかります。大きいファイル数。

答え3

私はあなたの目標に合わせてこのスクリプトを作成しました。

for files in *.extensions
do
  num=$(echo "$files" | awk '{print $1}' | cut -c1-2)
  if [ $num -gt 2 ]; then
     AS=$((num+2))
     temp=$(echo "$files" | cut -c 3-)
     mv $files 0$AS"$temp"
  fi
done

答え4

そしてzsh

$ autoload zmv
$ zmv -n -f '(<3->)(_*)(#qnOn)' '${(l:2::0:)$(($1+2))}$2'
mv -- 05_file_name.txt 07_file_name.txt
mv -- 05_file_name.log 07_file_name.log
mv -- 04_file_name.txt 06_file_name.txt
mv -- 04_file_name.log 06_file_name.log
mv -- 03_file_name.txt 05_file_name.txt
mv -- 03_file_name.log 05_file_name.log

その後、実際にこれを行うには、削除-n(模擬実行のため)します。

  • zmv pattern replacement:zmv強力な zsh glob および Spread 演算子を活用して複雑なファイル名を変更する自動ロード可能機能です。
  • <x-y>10進数xとyを一致させます。
  • (#q...)グローバル予選
  • nOn:ameのn数値rder o(大文字Oに反転)n。したがって、数字を増やしているので、05...必要に応じてそれより先に来ます。04...
  • ${(l:n::padding:)expansion}lパッド長延長N使用充填材。したがって、${(l:2::0:)}使用時の長さは0〜2に保ちます。
  • $(($1+2))、最初のキャプチャされたグループは2ずつ増加します。
  • $2:2番目のキャプチャグループ:先行番号の後に続く内容。

関連情報