ファイル名のドットを拡張子以外のアンダースコアに置き換える


9

誰かがファイル名を変更する方法について提案できますか:

head.body.date.txt

に:

head_body_date.txt

Unixで名前変更を行う単一行ステートメントはありますか?


9
それ.tar.gzは拡張機能だと思いますか?また、U&Lへようこそ!
EKons

2
LinuxではなくUnixを本当に意味しているのですか?どのUnix?
terdon

1
明白な答えはmv head.body.date.txt head_body_date.txtです。他の制限や実際の例がある場合は、これらで質問を更新してください。現在のところ、質問がその明示的な名前のファイルを参照しているか、すべてのファイルが特定の形式の単一のディレクトリを参照しているか、または特定の名前のディレクトリ階層を検索してこれらを変更したいかは不明です。
クサラナンダ

回答:


9

ファイル名を反復処理し、パラメータ拡張を使用して変換します。

for f in *.*.*.txt; do i="${f%.txt}"; echo mv -i -- "$f" "${i//./_}.txt"; done

パラメータ展開パターンは、ファイル名()内の${f//./_}すべて.のをに置き換え_ます$f

上記は予行演習を行い、実際の名前変更が行われるようにします。削除しechoます。

for f in *.*.*.txt; do i="${f%.txt}"; mv -i -- "$f" "${i//./_}.txt"; done

あなただけでなく、拡張機能を扱いたい場合.txt

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     echo mv -i -- "$f" "${pre//./_}.${suf}"; done

echo実際のアクションの削除を確認した後:

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     mv -i -- "$f" "${pre//./_}.${suf}"; done

一般的な、任意の数のドット、少なくとも1つ:

for f in *.*; do pre="${f%.*}"; suf="${f##*.}"; \
                 mv -i -- "$f" "${pre//./_}.${suf}"; done

任意の数のドットがある場合、一般的な方法はありますか?
CiprianTomoiagă2016年

1
@CiprianTomoiaga Do:for f in *.*; do ...; done
heemayl 2016年

*.*例ではパターンをまっすぐに置くことをお勧めします。これは、コードが固定数のドットでのみ機能するように見えるためです。
ilkkachu

@ilkkachuフェア、編集済み。
heemayl 2016年

どうもありがとうございました。そしていくつかの学習!
SG

4

perl基づいて、rename

$ rename -n 's/\.[^.]+$(*SKIP)(*F)|\./_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)
  • \.[^.]+$(*SKIP)(*F) このパターンをスキップして、代替の一致を探します
  • |\./_/gすべて.をに置き換える_

または、否定先読みを使用して

$ rename -n 's/\.(?![^.]+$)/_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)

問題がなければ、-nオプションを削除します


3
rename 's/\.(?=[^.]*\.)/_/g' *.txt

正規表現の置換を使用.して、ファイル名の最後のインスタンスを除くすべてを検索し(先読みなし)、それらをに置き換えます_*.*必要に応じて一般化します。

(この特定のバージョンのrenameはを介してインストールされているようですutil-linux)。私は使用していますUbuntu 12.04(はい、かなり古いマシンです)。


2

bash

old=head.body.date.txt oldb=${old%.*} olde=${old##*.} ; \
mv -- "$old" "${oldb//./_}.${olde}"

(1)mv --で始まる「古い」ファイル名から保護するには、を使用する必要があります-。(2)シェルに特別なスペースや文字(およびなど)を含む「古い」ファイル名から保護するために$old、引用符("$old")で囲む必要があります。(3)拡張機能にアンダースコアが含まれている、少し病的なケースでは、回答が失敗します。名前がに変更されます。*?head.body.date.t_xthead_body_date_t.xt
スコット

@スコット、ありがとう。上記の3つの項目すべてに従って、コードが調整されました。
agc

1

使用してmvsedそしてrev1行に:

mv "head.body.date.txt" "$(echo head.body.date.txt | rev | sed 's/\./_/2g' | rev)"

txt現在の担当者のすべてのファイルにそれを適用したい場合、どのようにmv機能するかによってグロブを使用するのは難しいように見えforますが、ワンライナーでループを行うことができます:

for file in *.txt; do mv "$file" "$(echo $file | rev | sed 's/\./_/2g' | rev)"; done

少し長くなりますが、ループ内のいくつかのパターンに一致させることができます。


2
(1)ああっ!しないでください$(ls …)。するだけfor file in *.txt。(2)さらに引用符を使用する必要があります:mv "$file" "$(…)"
スコット

スコットに感謝します。私はまだ殻の若い子供です、穏やかにしてください;)
バレンティンB.

後でrename考えてみると、他のいくつかの回答のように使用することで、答えがシンプルに聞こえますが
バレンティンB.

-1
 mv head.body.date.txt head_body_date.txt

一度に1つのファイルを作成するのと同じくらい簡単です。これをディレクトリ内で再帰的に実行するか、ディレクトリ全体に対して実行するかを指定しないため、これが最も便利で迅速なソリューションになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.