bash 스크립트 실행 중인 덮어쓰기 동작

12784 단어 Bashtech

개시하다


이 글의 목적은 bash가 실행 중인 스크립트 파일의 덮어쓰기가 어떻게 작동하는지 개인적인 흥미를 바탕으로 확인하는 것이지, 다음을 언급하는 것이 아니다.
https://www.iimc.kyoto-u.ac.jp/ja/whatsnew/information/detail/211228056999.html

bash 스크립트 파일을 덮어쓰는 동작


https://qiita.com/kitsuyui/items/d0048eeaa50293a92a60
상기 내용에 따라 실행 중echo foo에서 echo bar으로 변경하면 bar 표시됩니다.
#!/bin/sh
sleep 30
echo foo
손 옆에서 해봤는데 안 나왔어bar.SHEBANG을 bash로 변경하려 했으나 재현되지 않았다.
그러나 실행 중 cp로 다음 파일을 덮어쓰면 재현됩니다.
#!/bin/sh
sleep 30
echo bar
또 사용cp이 아닌 사용mv일 경우 재현되지 않는다.또한 echo bar로 작성된 스크립트tar를 아카이브하여 실행 중x으로 덮어쓴 곳에서 재현되지 않습니다.총괄은 아래와 같다.
했던 내용.
재현되지 않음
vim로 덮어쓰기
기색을 드러내지 않다
cp로 덮어쓰기
재현
데이터로 덮어쓰기
기색을 드러내지 않다
이 일로 미루어 보면 다음과 같은 결론을 얻을 수 있다.
bash는 스크립트를 실행할 때 통일적으로 읽지 않고 순서대로 파일을 읽기 때문에 같은 i-node 파일을 후속으로 읽습니다.i-node가 다른 경우 이미 열린 파일 설명자는 이전 파일에서 계속 읽을 수 있기 때문에 중복되지 않습니다.
Vim은 저장할 때 임시 파일에 파일을 쓴 다음 이름을 바꾸어 저장합니다. 이것이 Vim이 저장한 이유죠.실제로는 Vim입니다.
설정
:set backupcopy=yes
후 다시 시도하는 곳bar을 표시합니다.backupcopy는 기본적으로 편집 중인 파일을 통해 자동으로 판별auto하기 때문에 시도할 때 yes로 명확하게 설정해야 합니다.

bash 설치 확인


https://savannah.gnu.org/git/?group=bash evalstring.cparse_and_execute에서 명령을 처리하고 input.cwith_input_from_buffered_stream에서 읽을 준비를 합니다.버퍼의 읽기 주체y.tab.c는 분석기에서 직접 호출됩니다. 이 분석기는 fgets(2)에서 읽기와 동시에 실행되기 때문에 파일을 한 번에 읽지 않습니다.while/do에서 순환이 실행될 때 스크립트는 버퍼 메모리 형식으로 파일을 읽습니다. 파일을 다시 쓰면 목적지가 무엇인지 되돌려줍니다. 이 버퍼 메모리가 파일 시스템에서 다시 읽지 않으면 같은 순환을 재현합니다.따라서 done를 찾았을 때 되돌아오는 주소는 메모리에 있습니다.
bash가 이러쿵저러쿵 말하기보다는 I/O 파일 시스템에 있을 때 이것이 원자탄이다.같은 일을 했다면 어떤 조개껍질이나 언어 처리 시스템이든 일어날 수 있다.
이전의 php는 해석 결과를 AST로 유지하지 않았기 때문에 bash와 마찬가지로 YACC의 분석기에서 직접 처리를 실시하는 것이 생각납니다.

끝말


나는 bash 코드를 여러 번 읽었지만 스크립트의 읽기 주위는 읽지 않았기 때문에 보호되지 않은 모습을 볼 수 있었으면 좋겠다. 그리고 스크립트 처리 시스템에서 실행되는 스크립트 파일의 덮어쓰기가 더욱 두려웠다.
반복합니다. 이것은 bash의 문제가 아니라 I/O가 원자력으로 인한 문제가 아닙니다. 이 문제를 피하는 동시에 스크립트를 바꾸면 스크립트가 멈춘 것만 확인할 수 있습니다.mv를 사용하든지 rm&cp를 사용하든지 설치 명령을 사용하세요.

추기 2021/12/29


트위터에 데몬1995씨가 지적하고 확인한 후 리눅스의 대시(/bin/sh),zsh가 재현되고 FreeBSD의sh/bash가 재현되지 않았다.UNIX System-V를 재현한 것 같습니다.

추기 2021/12/30(1)


트위터에서 hdk FreeBSD로 재현할 수 없는 이벤트2 씨는 FreeBSD가 stdio의 버퍼 관계 때문에 512바이트 정도로 검증하는 것이 가장 좋다고 지적해 주십시오.
main1.c
#include <stdio.h>

int
main() {
  char buf[512];
  FILE* fp = fopen("test", "r");
  fgets(buf, sizeof(buf), fp);
  puts(buf);
  getchar();
  fgets(buf, sizeof(buf), fp);
  puts(buf);
  fclose(fp);
}
main2.c
#include <stdio.h>
#include <memory.h>

int
main() {
  char buf[512];
  FILE* fp = fopen("test", "w");
  memset(buf, '0', sizeof(buf));
  fwrite(buf, sizeof(buf), 1, fp);
  fflush(fp);
  getchar();
  memset(buf, '1', sizeof(buf));
  fwrite(buf, sizeof(buf), 1, fp);
  fclose(fp);
}
main1을 실행하고, 중지 중main2를 실행하며, main1에서 키를 두드려 계속 진행하는 곳에서 512바이트 이후에 읽습니다.따라서 FreeBSD도 재현할 수 있습니다.

추기 2021/12/30(2)


트위터에 기시초는 이 점을 지적했고 jobs.csync_buffered_stream에서lseek임을 알게 됐다.dup에서 만든 fd에 같은 편이량을 전달하기 위해 버퍼에서 먼저 읽은 부분을 되돌려 놓은 것 같습니다.
input.c
/* Seek backwards on file BFD to synchronize what we've read so far
   with the underlying file pointer. */
int
sync_buffered_stream (bfd)
     int bfd;
{
  BUFFERED_STREAM *bp;
  off_t chars_left;

  if (buffers == 0 || (bp = buffers[bfd]) == 0)
    return (-1);

  chars_left = bp->b_used - bp->b_inputp;
  if (chars_left) {
    lseek (bp->b_fd, -chars_left, SEEK_CUR);
  }
  bp->b_used = bp->b_inputp = 0;
  return (0);
}
버퍼 메모리의 읽기량이 딱 맞을 때도 이 현상이 발생하지만, 이것lseek은 이 현상이 발생하기 쉬운 것 같다.check_bash_input의 평론을 읽었는데 이 상황에 대한 대응인 것 같다.

좋은 웹페이지 즐겨찾기