findとawkを使用してtcshシェルスクリプトでファイル名の感嘆符を参照する方法は?

findとawkを使用してtcshシェルスクリプトでファイル名の感嘆符を参照する方法は?

ファイル名でスペース文字 " "、感嘆符 " !"、およびドル記号 " $"を検索し、各文字を下線 " _"に置き換えるスクリプトがあります。ただし、感嘆符付きのファイル名はまったく処理されません。現在のフォルダとすべてのサブフォルダから名前を変更するファイルを特定の深さまで検索します(ここではあまり関係ありません)。フォルダ名も同じように変更する必要があり、これがディープインターリーブが機能する理由です。

必須の名前変更スキームは次のとおりです。

This is cool!.txt     -->    This_is_cool_.txt
Thank$.log            -->    Thank_.log
Foo 1/Bar 2/a.txt     -->    Foo_1/Bar_2/a.txt

スクリプトは次のとおりです。

#!/bin/tcsh -f
  
foreach n ( 1 2 3 4 5 6 7 8 )
    find . -mindepth $n -maxdepth $n -name '*[ $\!]*' | fgrep -v \" | \
    awk '{printf "mv -i -- \"%s\" \"%s\"\n", gensub("!","\\\\\!","g",$0), gensub(" ","_","g",gensub("\\$","\\\\$","g",gensub("!","\\\\\!","g",$0)))}' | tcsh -cf
end 

\2つの感嘆符の前のバックスラッシュの数を変更しましたが、効果はありません。エラーメッセージは次のとおりです(バックスラッシュの数が偶数)。

awk: cmd. line:1: warning: escape sequence `\!' treated as plain `!'

それとも(明らかに)対話型シェルを開くシェルスクリプトですか? !時には何も起こりません(mv最初の引数にバックスラッシュが多すぎてファイルが見つからない場合のようです)。

PS:見てわかるように、"二重引用符 ""を含むファイルも機能できないため除外しました。これらの問題を解決する方法も提案してください。

ベストアンサー1

mvコマンドを合成してawkシェルにパイプするよりも直接呼び出す方が簡単です。

#!/bin/bash
#
find -mindepth 1 -maxdepth 8 -type f -name '*[ !$]*' -execdir
    bash -c 'for f in "$@"; do echo mv -- "$f" "${f//[ !$]/_}"; done' _ {} +

このバージョンはファイル名を変更しますが、ディレクトリ名は変更しません(質問に記載されているように)。実際にディレクトリ名を変更するには、このバリアントを使用してください。

find -mindepth 1 -maxdepth 8 -depth -name '*[ !$]*' -execdir
    bash -c 'for f in "$@"; do echo mv -- "$f" "${f//[ !$]/_}"; done' _ {} +

どちらの場合も、echoコマンドが期待どおりに実行されることに満足している場合は、コマンドを削除してください。対話型の名前変更に使用されますmv -i。下線はbash -c '...' _ {}サブシェルで実行されるコードの「名前」になります。これはマッピングされ、$0コードエラー(存在する場合)を報告するために使用されるため、bashそこに配置できます。ただsubshellラベルだけです。

おすすめ記事