파일 내용, 파일 이름, 디렉터리 이름, 허용되는 공백의 "대규모 교체"를 위한 Bash 기능

파일 내용, 파일 이름, 디렉터리 이름, 허용되는 공백의 "대규모 교체"를 위한 Bash 기능

내 Ubuntu 시스템에서는 파일 내용, 파일 이름, 디렉터리 이름을 "대부분 교체"해야 하는 경우가 많습니다. 예를 들어 소스 코드를 다른 애플리케이션의 템플릿으로 복사하는 경우입니다.

~/.bashrc작동하지만 찾기 또는 바꾸기 문자열에 공백이 있으면 실패하는 함수를 구성했습니다 . 나는 이것이 때문이라고 믿는다sed이 명령은 스크립트에서 공백을 허용하지 않으며CD경로에 공백이 포함되어 있으면 경로 변수 수정도 실패합니다.

매개변수는 ($1) 디렉터리, ($2) 검색 텍스트, ($3) 대체 텍스트입니다.

매개변수에 모두 공백이 포함될 수 있도록 이 스크립트를 개선할 수 있습니까?

deepreplace() {


    if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]
    then
        echo "A parameter is missing"
    else

        cd $1

        vfind=$2
        vreplace=$3 

        # Replace the string in file

        find . -type f -exec sed -i "s/$vfind/$vreplace/g" {} +

        # Replace the string in file names, then directories


        find . -type d -name "*$vfind*" | while read f; do mv $f $(echo $f | sed "s/$vfind/$vreplace/g"); done
        find . -type f -name "*$vfind*" | while read f; do mv $f $(echo $f | sed "s/$vfind/$vreplace/g"); done
    fi
}

답변1

의견에서 언급했듯이 순수한 bash 솔루션이 내 사용 사례에 적합하지 않다고 확신합니다.

저는 Node.js/npm에 의존하는 명령을 선택했습니다(Node는 Unix가 아닌(Windows/Mac)를 포함하여 제가 작업하는 환경에서 매우 일반적이기 때문입니다).

두 개의 npm 패키지에 따라 다름이름 바꾸기그리고바꾸다.

이러한 라이브러리를 사용하면 정규식과 기타 고급 이름 바꾸기/교체 시나리오를 지원한다는 이점이 있습니다.

Node.js/npm을 설치한 후:

# Globally install the required packages (this prevents npx from trying to install in current directory if they do not already exist)

$ npm install -g renamer
$ npm install -g replace

# Set variables (dir, find, replace) for directory, find and replace strings, then run change directory, rename and replace, before reverting to original directory.
# npx is not strictly required, but have included to prevent collisions with command names on the PATH.

$ dir="./example_dir" && 
   find="example_find" && 
     replace="example_replace" && 
       cd "$dir" && 
        npx renamer --find "$find" --replace "$replace" "**" && 
            npx replace "$find" "$replace" . -r 
                && cd -

동등한 .bashrc 함수는 다음과 같습니다.

renamereplace() {

    # Install global packages if not installed

    npm list -g renamer || npm install -g renamer
    npm list -g replace || npm install -g replace

    # Alias positional arguments

    dir="$1"
    find="$2"
    replace="$3" 

    # Change to replace directory

    cd "$dir"

    # Rename in directory and file names

    npx renamer --find "$find" --replace "$replace" "**" 

    # Replace in file contents

    npx replace "$find" "$replace" . -r 

    # Revert current directory

    cd -
}

다음을 통해 호출할 수 있습니다.

$ renamereplace "./example_dir" "example_find" "example_replace"

고지 사항: 데이터 손실을 방지하려면 a) 이 스크립트를 이해하고, b) 이 명령이 실행될 디렉터리를 확인하고, c) 위 명령을 실행하기 전에 모든 중요한 데이터를 백업했는지 확인하십시오.

답변2

귀하의 함수는 귀하가 원하는 거의 모든 작업을 수행합니다. 변수 및 대체 항목 주위에 따옴표가 많이 없기 때문에 파일 이름의 공백에 저항하지 않습니다.

  • 변수: "$1", "$2", "$f" 등
  • 바꾸기: "$(...)"

첫 번째 로우터치 리뷰는 다음과 같습니다.

deepreplace() {
  if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]
  then
      echo "A parameter is missing"
  else
    cd "$1" # quote missing
    vfind="$2" # quote missing
    vreplace="$3" # quote missing
    # Replace the string in file contents
    find . -type f -exec sed -i "s/$vfind/$vreplace/g" {} +
    # Replace the string in directory names
    find . -type d -name "*$vfind*" |
    while read d ; do
      mv "$d" "$(echo "$d" | sed "s/$vfind/$vreplace/g")"
    done
    # Replace the string in file names
    find . -type f -name "*$vfind*" |
    while read f; do
      mv "$f" "$(echo "$f" | sed "s/$vfind/$vreplace/g")"
    done
  fi
}

다음 개선 사항:

  • $(echo $v | sed s/x/y/g)내장된 예제를 사용하는 대신 ${v//x/y}
    mv "$f" "${f//$vfind/$vreplace}"
  • 디렉터리 수준 위의 경로를 바꾸려는 경우 문제가 발생합니다. 따라서 파일을 찾은 다음 디렉터리를 찾는 대신 디렉터리를 먼저 대상으로 지정한 다음 파일을 대상으로 지정합니다.
  • find세 번 실행해도 소용없어요

새로운 순수 bash 접근 방식은 다음과 같습니다.

    find . | while read p ; do
      ddir="$(dirname "${p//$vfind/$vreplace}")"
      obas="$(basename "$p")"
      nbas="${obas//$vfind/$vreplace}"
      # if object rename
      [[ $obas != $nbas ]] && mv "$ddir/$obas" "$ddir/$nbas"
      # if object is file, edit
      [ -f "$ddir/$nbas" ] && sed -i "s/$vfind/$vreplace/g" "$ddir/$nbas"
    done
  • find자연스러운 출력 순서는 디렉토리가 항상 하위 디렉토리보다 먼저 이름이 바뀌는 것과 같으므로 기본 이름 요소만 이름을 바꾸는 것이 안전합니다.
  • 모든 이름에는 공백을 안전하게 포함할 수 있습니다.
  • 단 한 사람만이 find더 낮은 비용으로 작업을 수행합니다.
  • 종속성을 js에 저장합니다.

관련 정보