スクリプトを使用したテキストファイルの名前変更

スクリプトを使用したテキストファイルの名前変更

フォルダには何千ものテキストファイルがあり、特定の方法で名前が付けられます。

たとえば、

Image_234_Data_7778_n0.txt
Image_234_Data_7778_n1.txt
Image_234_Data_7778_n2.txt

Image_954_Data_4478_n0.txt
Image_954_Data_4478_n1.txt
Image_954_Data_4478_n2.txt

Image_104_Data_9878_n0.txt
Image_104_Data_9878_n1.txt
Image_104_Data_9878_n2.txt

など...

内容が次のようなソースファイル(ファイル名を変更して「何が何であるか」を追跡するために使用されます)を作成したいと思います。

1_1.txt:Image_234_Data_7778_n0.txt
1_2.txt:Image_234_Data_7778_n1.txt
1_3.txt:Image_234_Data_7778_n2.txt

2_1.txt:Image_954_Data_4478_n0.txt
2_2.txt:Image_954_Data_4478_n1.txt
2_3.txt:Image_954_Data_4478_n2.txt

3_1.txt:Image_104_Data_9878_n0.txt
3_2.txt:Image_104_Data_9878_n1.txt
3_3.txt:Image_104_Data_9878_n2.txt

など...

誰もが私のためにこれを行うコードを書くのに役立ちますか?

答え1

私はあなたのファイル名が数字で終わらず、一連の数字であるランダムなテキストXXXXNNN.txt形式であり、同じXXXにグループ化したいとします。XXXXNNN

戦略:アルファベット順にファイルを繰り返し、XXXXセクションが変更された時期を検出します。各グループに新しい名前を生成します。 1つのマイナーな問題は、NNN部分が可変幅の場合、アルファベット順にソートされないことです。 NNN=10 は NNN=1 と NNN=2 の間に表示されます。

current=
numbers=
i=0
for x in *.txt ''; do
  stem=${x%.*}
  n=${stem##*[!0-9]}
  stem=${stem%$n}
  if [ "$stem" != "$current" ]; then
    for k in $(printf '%s\n' $numbers | sort -n); do
      y=${i}_${k}.txt
      echo mv "$current$k.txt" "$y"
    done
    current=$stem
    numbers=$n
    i=$((i+1))
  else
    numbers="$numbers $n"
  fi
done

ファイル名の変更、ファイルへの情報の書き込みecho mvなど、使用したいコマンドに置き換えます。mvecho …

ファイル名を変更して以前の名前を追跡する代わりに、次のものを使用することをお勧めします。シンボリックリンク元の名前と単純化された名前を使用してファイルにアクセスできます。

答え2

次のファイルを含むテストディレクトリを作成した後:

Image_104_Data_9878_n0.txt, Image_104_Data_9878_n1.txt,
Image_234_Data_7778_n0.txt, Image_234_Data_7778_n1.txt,
Image_234_Data_7778_n2.txt, Image_954_Data_4478_n0.txt,
Image_954_Data_4478_n1.txt, Image_954_Data_4478_n2.txt

それから私は次のことをしました。

printf %s\\n * | sort --debug -t_ -k2,2n -k5.2n,5.2n 

結果:

Image_104_Data_9878_n0.txt
      ___
                     _
__________________________
Image_104_Data_9878_n1.txt
      ___
                     _
__________________________
Image_234_Data_7778_n0.txt
      ___
                     _
__________________________
Image_234_Data_7778_n1.txt
      ___
                     _
__________________________
Image_234_Data_7778_n2.txt
      ___
                     _
__________________________
Image_954_Data_4478_n0.txt
      ___
                     _
__________________________
Image_954_Data_4478_n1.txt
      ___
                     _
__________________________
Image_954_Data_4478_n2.txt
      ___
                     _
__________________________

sortたとえば、2cdで区切られたフィールドでは、フィールドの先頭からフィールドの終わりまでの数字に基づいて主にソートし、5番目のフィールドの2番目の2cdバイトに基づいて数字に基づいてソートするように指示されました。私はそれが正確に何をしているのかを知らせるために出力を要求しました。_-k2,2n-k5.2,5.2n--debug

主にフィールド4、主にフィールド2、2番目はフィールド5.2、最も重要ではないものは2番目のフィールドに簡単に配置できます。あなたの例で提供されている順序の韻や理由を特定できないので、これを言うことです。あなたはこれを次のように割り当てたと仮定することができます。

  • 1_1:234/7778
  • 2_1:954/4478
  • 3_1:104/9878

...これまでの並べ替えのための適切なコマンドを作成していないので、これを行う方法についてのアドバイスが必要な場合があります。この仮定に基づいて、私は次のようにします。

printf %s\\n * | 
sort -t_ -k4,4n -k5.2n,5.2n | 
nl -bp'_n0\.' -s_ |
sed 's/\(I[^.]*_n\)\(.*\)/\2:\1\2/;N
     s/ *\([0-9]*_\)\(.*\n\) *\([^_]*I\)/\1\2\1\3/;P;D'

私はこれがあなたが探しているものと非常に近い結果を生み出すと思います。願いより?

1_0.txt:Image_954_Data_4478_n0.txt
1_1.txt:Image_954_Data_4478_n1.txt
1_2.txt:Image_954_Data_4478_n2.txt
2_0.txt:Image_234_Data_7778_n0.txt
2_1.txt:Image_234_Data_7778_n1.txt
2_2.txt:Image_234_Data_7778_n2.txt
3_0.txt:Image_104_Data_9878_n0.txt
3_1.txt:Image_104_Data_9878_n1.txt

私が指定したので、4番目のフィールドに基づいてソートされ、番号が付けられますが、-k4,4n指示に従うのはsort簡単です。-k2,2n

nlこのコマンドは、文字列を含む行にのみ番号を付けるように要求することで機能します_n0.sed次のように出力を受け取ります。

 1_Image_954_Data_4478_n0.txt
   Image_954_Data_4478_n1.txt
   Image_954_Data_4478_n2.txt
 2_Image_234_Data_7778_n0.txt
   Image_234_Data_7778_n1.txt
   Image_234_Data_7778_n2.txt
 3_Image_104_Data_9878_n0.txt
   Image_104_Data_9878_n1.txt

...最初に_n[0-9]*.txtビットを行の先頭にコピーし、Nextは次の行を取得します。パターンスペースが次の場合:

 *num_.*\n [^_]*I

... この時点で、1 行目の数値ビットを 2 行目に追加します。このコマンドで生成されたテキストファイルから移動操作に移動するには、次のようにします。

sed 's/\([^:]*\):\(.*\)/$* \2 \1/' <txtfile |
sh -s -- echo mv

出力

mv Image_954_Data_4478_n0.txt 1_0.txt
mv Image_954_Data_4478_n1.txt 1_1.txt
mv Image_954_Data_4478_n2.txt 1_2.txt
mv Image_234_Data_7778_n0.txt 2_0.txt
mv Image_234_Data_7778_n1.txt 2_1.txt
mv Image_234_Data_7778_n2.txt 2_2.txt
mv Image_104_Data_9878_n0.txt 3_0.txt
mv Image_104_Data_9878_n1.txt 3_1.txt

シェルプロセスの最初の引数なので、ちょうどedとマークされていますが、先ほど行ったようにechoそれを削除して実行すると、同じ結果が得られます。

ls -m

1_0.txt, 1_1.txt, 1_2.txt, 2_0.txt, 2_1.txt, 2_2.txt, 3_0.txt, 3_1.txt

Gillesは良いアイデアだと思うリンクをお勧めしますが、個人的にはソフトリンクを避け、可能であればミラーリングされたハードリンクディレクトリを作成します。ほぼ同じ方法でこれを実行できますが、代わりに使用することをお勧めしlnますmv

答え3

このような問題を解決する1つの方法(特にスクリプトに精通していない場合)は、スプレッドシートを使用してスクリプトを生成することです。再利用可能なスクリプトを作成する場合は、これは良い方法ではありませんが、他の方法でスクリプトを作成する方法を学ぶ時間がない人のためのワンタイムタスクに役立ちます。

達成したい名前の変更(または接続)は、aの前のすべてをaの_n前の単一のシーケンス番号に変更_し、残りは_n変更されていないままにするようです。正確な意図ではない場合は、スプレッドシートの式を簡単に修正できます。

たとえば、(水平スクロールの必要性を減らすためにファイル名を減らします):

A2               B2             C2           D2           E2
i234d7778_n0.txt =FIND("_n",A2) =LEFT(A2,B2) =D1+(C2<>C1) =D2&"_"&RIGHT(A2,LEN(A2)-B2-1)
i234d7778_n0.txt 10             i234d7778_   1            1_0.txt

行1ではなく行2から始まる理由は、D2の比較が行1に進むからである。 (代替案は最初の行に配置することですが、特別な場合はD1は行1に配置されます。)

D2の式は簡単に言うと次のようになります。=IF(C2=C1,D1,D1+1)

スプレッドシートと同様に、ファイルのリストを列Aに貼り付け、ファイルの数に応じて列Bから列Eまで繰り返します。名前変更を実行するスクリプトを生成するには、「F」または「G」列を追加します。

F2                          G2
="mv "&A2&" "&E2            ="ln "&A2&" new-name-directory/"&E2
mv i234d7778_n0.tx 1_0.txt  ln i234d7778_n0.tx new-name-directory/1_0.txt

列と列Gは、実行可能なスクリプトのテキストを提供します。

関連情報