再帰的検索/置換(ディレクトリの深さを考慮)

再帰的検索/置換(ディレクトリの深さを考慮)

私は基本的な検索/置換で幸運になりました。

find . -name "*.php" -exec sed -i -e "s/<?php include 'http:\/\/www/<?php include '..\//g" \{\} \;

同様の結果を得る方法があるかどうか疑問に思います。しかし、現在のディレクトリの「深さ」を考慮し、構造../の各レベルの代替文字列の前に追加を追加しますか?

答え1

次のように試すことができます。

find . -name '*.php' -exec sh -c \
'PREFIX=${1//[!/]/}; PREFIX=${PREFIX//\//..\/}; ...' sh {} \;

見つかったファイルが裏面に設定されますPREFIX。その後、シェル変数を使用してその場所にコマンドを挿入できます。../dir/filenamesed...$PREFIX

これには${var//find/repl}拡張機能を備えたシェルが必要です。これはPOSIXでは指定されていませんが、Bash一部のPOSIX実装ではash指定されています。それ以外の場合は、プレフィックスを実行するには別のものを使用する必要があります。この場合、単一のawkプロセスを使用してそのセクションでプレフィックス操作を実行し、(別々のプロセスの代わりにBEGIN)ファイルの各行で置換を実行します。sed

答え2

サイトルートに関連付けられているディレクトリの深さに依存するベースURLを強制的に適用する同様の作業がありました。

完全なソリューションは以下に掲載されています。 @dubiousjimの答えに基づいていますが、引用の問題を避けるために、シェル機能を使用して少し異なるアプローチをとります。

fixlinks() {
  # strip the first level depth as we don't need it
  BASE=${1/#\.\//}
  # leave only one slash char for each nested dir
  BASE=${BASE//[!\/]/}
  # replace each / with ../ (escaped to ..\/ to be used as sed replacement part)
  BASE=${BASE//\//..\\\/} 
  if [[ $BASE ]]; then
    # enable debug mode
    set -x
    # add <base> tag leading to site root after <head> for each nested file
    sed -E -i "s/<head>\r?$/<head><base href=\"$BASE\"\/>/g" "$1"
    # silently disable debug mode
    { set +x; } 2>/dev/null
  fi
}
# iterate over all files from the site root
find . -name '*.html' | while read file; do fixlinks "$file"; done

関連情報