내 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에 저장합니다.