유닉스에서, 대부분의 편집자들은 편집 된 내용을 포함하는 새로운 임시 파일을 만들어 작업합니다. 편집 된 파일이 저장되면 원본 파일이 삭제되고 임시 파일 이름이 원래 이름으로 바뀝니다. (물론, 데이터 손실을 방지하기위한 다양한 보호 수단이 있습니다.) 예를 들어, 실제로는 "in-place"가 아닌 ( "in-place") 플래그로 사용 sed
하거나 perl
호출 할 때 사용되는 스타일 -i
입니다. 그것은 "오래된 이름을 가진 새로운 장소"라고 불렸어야했다.
유닉스는 열린 파일이 "삭제"되어 같은 이름의 새로운 파일이 생성 되더라도 파일이 닫힐 때까지 열린 파일이 계속 존재하기 때문에 (적어도 로컬 파일 시스템의 경우) 확실하게 작동합니다. (파일을 "삭제"하는 유닉스 시스템 호출을 실제로 "unlink"라고하는 것은 우연이 아닙니다.) 일반적으로 쉘 인터프리터에 소스 파일이 열려 있고 위에서 설명한 방식으로 파일을 "편집"하면 쉘은 원본 파일이 여전히 열려 있기 때문에 변경 사항을 볼 수 없습니다.
[참고 : 모든 표준 기반 주석과 마찬가지로 위의 내용은 여러 가지 해석이 가능하며 NFS와 같은 다양한 사례가 있습니다. Pedants는 예외적으로 의견을 채울 수 있습니다.]
물론 파일을 직접 수정하는 것도 가능합니다. 파일의 데이터를 덮어 쓸 수는 있지만 다음 데이터를 모두 이동하지 않으면 삭제하거나 삽입 할 수 없으므로 다시 쓰기 작업이 많이 필요하기 때문에 편집 목적으로는 그다지 편리하지 않습니다. 또한 이러한 이동을 수행하는 동안 파일의 내용을 예측할 수 없으며 파일을 연 프로세스에 문제가 생길 수 있습니다. 이를 해결하려면 (예 : 데이터베이스 시스템과 같이) 정교한 수정 프로토콜과 분산 잠금 세트가 필요합니다. 일반적인 파일 편집 유틸리티의 범위를 벗어나는 것.
따라서 쉘에서 파일을 처리하는 동안 파일을 편집하려면 두 가지 옵션이 있습니다.
파일에 추가 할 수 있습니다. 항상 작동해야합니다.
정확히 같은 길이의 새 내용 으로 파일을 덮어 쓸 수 있습니다 . 쉘이 파일의 해당 부분을 이미 읽었는지 여부에 따라 작동하거나 작동하지 않을 수 있습니다. 대부분의 파일 I / O에는 읽기 버퍼가 포함되어 있기 때문에 모든 셸에서 실행하기 전에 전체 복합 명령을 읽으므로이를 피할 수 없을 것입니다. 확실하지 않을 것입니다.
Posix 표준의 문구에 대해서는 실제로 파일을 실행하는 동안 스크립트 파일에 추가해야 할 가능성이 있으므로 모든 Posix 호환 쉘에서 작동하지 않을 수 있습니다. 때로는 POS 호환 쉘도 있습니다. YMMV입니다. 그러나 내가 아는 한, bash와 안정적으로 작동합니다.
증거로, 여기에 bash에서 악명 높은 99 병의 맥주 프로그램을 "루프 프리 (loop-free)"구현 dd
으로 덮어 쓰고 추가 하는 데 사용 합니다 (덮어 쓰기는 현재 실행중인 줄을 대체하기 때문에 아마도 안전합니다. 정확히 동일한 길이의 주석이있는 파일; 자체 수정 동작없이 최종 결과를 실행할 수 있도록했습니다.)
#!/bin/bash
if [[ $1 == reset ]]; then
printf "%s\n%-16s#\n" '####' 'next ${1:-99}' |
dd if=/dev/stdin of=$0 seek=$(grep -bom1 ^#### $0 | cut -f1 -d:) bs=1 2>/dev/null
exit
fi
step() {
s=s
one=one
case $beer in
2) beer=1; unset s;;
1) beer="No more"; one=it;;
"No more") beer=99; return 1;;
*) ((--beer));;
esac
}
next() {
step ${beer:=$(($1+1))}
refrain |
dd if=/dev/stdin of=$0 seek=$(grep -bom1 ^next\ $0 | cut -f1 -d:) bs=1 conv=notrunc 2>/dev/null
}
refrain() {
printf "%-17s\n" "# $beer bottles"
echo echo ${beer:-No more} bottle$s of beer on the wall, ${beer:-No more} bottle$s of beer.
if step; then
echo echo Take $one down, pass it around, $beer bottle$s of beer on the wall.
echo echo
echo next abcdefghijkl
else
echo echo Go to the store, buy some more, $beer bottle$s of beer on the wall.
fi
}
####
next ${1:-99} #