안녕하세요, 저는 2개의 기호를 가져와 첫 번째 기호를 두 번째 기호로 바꾸는 스크립트를 작성 중입니다. 스크립트는 이를 매개변수 파일로도 사용합니다. 아이디어는 파일의 첫 번째 문자를 두 번째 문자로 바꾸는 것입니다. 스크립트는 다음과 같습니다.
char_src=$1
char_dest=$2
shift
for file
do
while read -r line
do
line=${line//$char_src/$char_dest}
echo "$line"
done < "$file"
done
문제는 올바른 내용을 인쇄하지만 변경 사항을 파일에 저장하지 않는다는 것입니다. done < "$file"
답변1
먼저 쉬운 부분: 쉘에서 파일을 한 줄씩 읽는 것이 느리므로 대신 이것을 사용할 수 있습니다 tr
. man tr
자세히보다.
둘째, 임시 파일이 필요합니다. 파일을 동시에 읽고 쓸 수는 없습니다(어차피 쉘에서는 불가능). 따라서 다음과 같이 해야 합니다.
tr -- "$1" "$2" <"$file" >"$file".tmp
mv -f -- "$file".tmp "$file"
분명한 질문은 tr
어떤 이유로든(예: $1
비어 있는 경우) 실패하면 어떻게 되는지입니다. 그런 다음 $file.tmp
여전히 생성된 다음(쉘이 행을 구문 분석할 때 생성됨) $file
대체됩니다.
따라서 더 안전한 접근 방식은 다음과 같습니다.
tr -- "$1" "$2" <"$file" >"$file".tmp && \
mv -f -- "$file".tmp "$file"
이제 $file
성공한 경우에만 교체됩니다.tr
하지만 주변에 다른 파일 이름이 있으면 어떻게 될까요 $file.tmp
? 글쎄, 그것은 다루어질 것이다. 여기서 상황이 더욱 복잡해집니다. 기술적으로 올바른 방법은 다음과 같습니다.
tmp="$( mktemp -t "${0##*/}"_"$$"_.XXXXXXXX )" && \
trap 'rm -f "$tmp"' EXIT HUP INT QUIT TERM || exit 1
tr -- "$1" "$2" <"$file" >"$tmp" && \
cat -- "$tmp" >"$file" && \
rm -f -- "$tmp"
이렇게 하면 mktemp
임시 파일이 생성됩니다. trap
스크립트가 정상적으로 또는 비정상적으로 종료되면 파일이 정리되고 cat -- "$tmp" >"$file"
대신 권한 mv
이 $file
유지됩니다. 쓰기 권한이 없으면 $file
여전히 실패할 수 있지만 임시 파일은 결국 삭제됩니다.
또는 GNU에는 sed
파일을 그 자리에서 편집할 수 있는 옵션이 있으므로 다음을 수행할 수 있습니다.
sed -i "s/$1/$2/g" "$file"
그러나 이는 보기만큼 간단하지 않습니다. $1
또는 for가 특별한 의미를 갖는 경우 $2
위 작업은 실패합니다 sed
. 따라서 먼저 이스케이프해야 합니다.
in=$( printf '%s\n' "$1" | sed 's:[][\/.^$*]:\\&:g' )
out=$( printf '%s\n' "$2" | sed 's:[\/&]:\\&:g;$!s/$/\\/' )
sed -i "s/$in/$out/" "$file"
답변2
이 목적을 위해 특별히 제작된 도구가 있다는 사실은 지금은 무시하세요.
char_src=$1
char_dest=$2
shift
shift 2
여기서 일반 파일을 shift
이동 $2
하고 $1
첫 번째 파일 이름을 남겨두기를 원할 수 있습니다 .
while read -r line
올바르게 사용하고 있지만 read -r
기본값을 사용하면 IFS
앞뒤 read
공백이 제거됩니다.
done < "$file"
<
리디렉션 전용입력하다, 필요한 출력을 리디렉션 > "$file2"
하고 여러 위치에 명시된 대로(예를 들어 여기), 동일한 파일로 리디렉션하면 아무것도 읽기 전에 파일이 잘립니다.
이를 위해 만들어진 도구는 단일 문자를 다른 단일 문자로 변경하려면 를 사용하십시오 tr
. 쉘 ${var//pat/repl}
구성은 전체 문자열을 대체하며 s/pat/repl/g
in 와 더 유사합니다 sed
.