0

フォルダのリストがあります。たとえば、各フォルダの名前は次のとおりです。

  • ファイルpippo1.txtを含むpippo1、
  • ファイルpippo2.txtを含むpippo2、
  • pippo3.txtなどのファイルを含むpippo3。

最初のフォルダーに移動し、ファイル名pippo1.txtから番号を削除してから終了し、ファイルpippo2.txtを含むpippo2という2番目のフォルダーに移動し、ファイル名から2を削除します。コードですが、機能しません!コードは次のとおりです。

for i in *
do
    cd $i
    ls *.txt | sed -e "s/[0-9]//g"
    cd ..
done

私は何が間違っているのですか?

4

2 に答える 2

2

ディレクトリを切り替えるときは、サブシェルを呼び出すのが最善で最もクリーンです。

ファイルの名前を変更するときは、通常、ローカルコマンドを使用するrenameか、ローカルコマンドを取得するのが最適です。問題は、いくつかの「標準」renameコマンドがあり、より広く配布されているコマンドは、Perlベースのコマンドよりもはるかに強力ではないということです。このアプローチは回避renameしますが、完全に望ましいわけではありません。

for dir in *
do
    (
    cd "$dir"
    for file in *[0-9].txt
    do
        mv "$file" $(echo "$file" | sed 's/[0-9]\.txt$/.txt/')
    done
    )
done

Perlベースrenameは、最初の引数として正規表現を取り、それをファイル名に適用します。

for dir in *
do
    (
    cd "$dir"
    rename 's/\d\.txt$/.txt/' *[0-9].txt
    )
done

これはより信頼性があります。

于 2012-07-09T18:41:10.213 に答える
2

要件が非常に単純な場合は、bashの置換のみでこれを行うことができます。

for file in `find . -name 'pippo*.txt'`; do
    mv $file ${file/[0-9].txt/.txt}
done

ただし、これはファイル名の1桁を超える場合は失敗しますpippo999/pippo999.txt。これは、extglobオプションを設定することで対処できます。

shopt -s extglob
for file in `find . -name 'pippo*.txt'`; do
    mv $file ${file/+([0-9]).txt/.txt}
done

bashファイルグロブの+(...)構成は、が設定されている場合にのみ使用できますextglob

ループとでディレクトリツリーをトラバースする代わりにcd、これはfind関連するすべてのファイルのリストを取得するために使用し、ファイル名のリストをループします。これは次の形式になります./pippoN/pippoN.txt。名前の変更では、bashパラメーターの置換を使用して、変更されたファイル名を取得します。ファイル名の展開も参照してください。

ファイル名またはディレクトリ名のスペースは、このアプローチを破ることに注意してください。スペースを含むfindパスは、スペースの周りの複数のトークンに分割され、各トークンはリストイテレータの個別の結果になります。したがって、パス内のスペース文字を予測する必要がある場合、これはもう少し複雑になります。

shopt -s extglob
IFS=$'\n'
for file in `find . -name 'pippo*.txt'`; do
    mv "$file" "${file/+([0-9]).txt/.txt}"
done

ここでは、mvスペースを正しく処理するコマンドのファイル名を引用し、 IFSbashが空白を単語の境界として認識しないようにフィールド区切り文字を変更しました。findこれにより、ループイテレータの問題が修正されます。これで、パス内のスペースが正しく処理されるようになり、たとえば、./pippo 9/pippo9.txt名前も次のように変更されます./pippo 9/pippo.txt

于 2012-07-09T19:10:53.447 に答える