引子
跟踪perl和python脚本对文件的访问,实际过程中,perl和python解析器在解析完脚本后,直接关闭了
脚本文件,在进程中查询不到是访问文件的脚本文件名称。
shell、perl和python脚本执行过程
bash脚本执行过程
脚本内容:
#!/usr/bin/env bash echo `date`" hello world!" >> /root/log.txt
使用strace跟踪脚本执行过程,为了节省篇幅,只保留一些关键执行过程:
# strace -q ./test.sh
execve("./test.sh", ["./test.sh"], [/* 35 vars */]) = 0 ##启动脚本进程
......
open("./test.sh", O_RDONLY) = 3 ##打开脚本文件
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff37bb77d0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR) = 0
read(3, "#!/usr/bin/env bash\n\necho `date`"..., 80) = 66
lseek(3, 0, SEEK_SET) = 0
getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=4*1024}) = 0
fcntl(255, F_GETFD) = -1 EBADF (Bad file descriptor)
dup2(3, 255) = 255 ##复制已打开的脚本文件描述符为255
close(3) = 0 ##关闭已打开的脚本文件描述符3
......
read(255, "#!/usr/bin/env bash\n\necho `date`"..., 66) = 66 ##读取test.sh脚本内容
.....
open("/root/log.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3 ## 执行test.sh脚本中打开日志文件的动作
....
read(3, "Sun Feb 3 16:15:31 CST 2019\n", 128) = 29 ## 获取date命令结果
read(3, "", 128) = 0
.....
write(1, "Sun Feb 3 15:51:56 CST 2019 hell"..., 41) = 41 ## 执行test.sh脚本中写日志文件的动作
dup2(10, 1) = 1
fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(255, "\n", 66) = 1
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(255, "", 66) = 0
exit_group(0) = ? ##退出shell脚本执行,这里会关闭所有打开的文件描述符
ksh脚本执行过程:
#!/usr/bin/env ksh echo `date`" hello world!" >> /root/log.txt
strace -q ./test.sh
execve("./test.sh", ["./test.sh"], [/* 35 vars */]) = 0 ##启动脚本进程
......
open("./test.sh", O_RDONLY) = 3 ##打开脚本
fstat(3, {st_mode=S_IFREG|0755, st_size=65, ...}) = 0
fcntl(3, F_DUPFD, 10) = 10 ##复制脚本文件的描述符
close(3) = 0 ## 关闭脚本文件
/*
open("./test.sh", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=65, ...}) = 0
fcntl(3, F_DUPFD, 10) = 11 ##有的系统得出的结果是11
close(3) = 0
fcntl(11, F_SETFD, FD_CLOEXEC) = 0
*/
......
read(10, "#!/usr/bin/env ksh\n\necho `date`\""..., 8192) = 65 ##读脚本文件内容
read(10, "", 8192) = 0
brk(0xf09000) = 0xf09000
......
read(3, "Sun Feb 3 16:24:53 CST 2019\n", 8192) = 29 ##获取date命令内容
read(3, "", 8192) = 0
close(3) = 0
......
write(3, "Sun Feb 3 16:24:53 CST 2019\n", 29) = 29
......
open("/root/log.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3 ##打开日志文件
......
write(1, "Sun Feb 3 16:24:53 CST 2019 hell"..., 41) = 41 ##写日志文件
lseek(1, 0, SEEK_CUR) = 492
......
exit_group(0) = ? ##退出shell脚本执行,这里会关闭所有打开的文件描述符
perl脚本执行过程
#!/usr/bin/env perl $datestring = localtime(); open(logfile,">>/mnt/newlog3.txt") or die "Cant't open /mnt/newlog3.txt";
print logfile "$datestring hello world! I am Perl!\n";
close(logfile);
# strace /usr/bin/perl ../hello.pl
execve("/usr/bin/perl", ["/usr/bin/perl", "../hello.pl"], [/* 62 vars */]) = 0 ##执行hello.pl脚本
......
open("../hello.pl", O_RDONLY) = 3 ##以下代码是打开hello.pl脚本并读取脚本内容(包含脚本解析)
......
read(3, "#!/usr/bin/env perl\n\n$datestring"..., 4096) = 194
read(3, "", 4096) = 0
close(3) = 0 ## 关闭已经打开的hello.pl脚本
open("/etc/localtime", O_RDONLY) = 3 ## 打开时间文件,获取时间:对应脚本第三行
fstat(3, {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb976b7b000
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 414
lseek(3, -249, SEEK_CUR) = 165
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 249
close(3) = 0
munmap(0x7fb976b7b000, 4096) = 0
open("/mnt/newlog3.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3 ##打开日志文件 /mnt/newlog3.txt:对应脚本第5和6行
lseek(3, 0, SEEK_END) = 389
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7ffd3b444fb0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR) = 389
fstat(3, {st_mode=S_IFREG|0644, st_size=389, ...}) = 0
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
write(3, "Mon Feb 11 18:31:40 2019 hello w"..., 49) = 49
close(3) = 0 ##关闭日志文件 /mnt/newlog3.txt
exit_group(0) = ?
python脚本执行过程
#!/usr/bin/python import os
import datetime,time with open("/mnt/newlog3.txt", 'a+') as fp:
cur_date=datetime.datetime.now()
cur_date_str=cur_date.strftime("%Y-%m-%d %H:%M:%S")
fp.write("{0} Hello world! I am python!\n".format(cur_date_str))
fp.close()
# strace ./hello.py
execve("./hello.py", ["./hello.py"], [/* 62 vars */]) = 0 ##执行hello.py脚本
......
getcwd("/root/liangjs", 4096) = 14
lstat("/root/liangjs/hello.py", {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
stat("./hello.py", {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
open("./hello.py", O_RDONLY) = 3 ##打开hello.py脚本并解析该python脚本
fstat(3, {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f67ad9e8000
fstat(3, {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
lseek(3, 0, SEEK_SET) = 0
read(3, "#!/usr/bin/python\n\nimport os\nimp"..., 241) = 241
read(3, "e_str))\n\tfp.close()\n\n\n", 4096) = 22
close(3) = 0
munmap(0x7f67ad9e8000, 4096) = 0
stat("./hello.py", {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
open("./hello.py", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff46f2d390) = -1 ENOTTY (Inappropriate ioctl for device)
fstat(3, {st_mode=S_IFREG|0750, st_size=263, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f67ad9e8000
lseek(3, 0, SEEK_CUR) = 0
read(3, "#!/usr/bin/python\n\nimport os\nimp"..., 4096) = 263
lseek(3, 263, SEEK_SET) = 263
brk(0x6c7000) = 0x6c7000
read(3, "", 4096) = 0
brk(0x6be000) = 0x6be000
brk(0x6bc000) = 0x6bc000
close(3) = 0 ##关闭已经打开的hello.py脚本文件
munmap(0x7f67ad9e8000, 4096) = 0
......
open("/etc/localtime", O_RDONLY) = 4 ##获取时间信息
fstat(4, {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
fstat(4, {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f67ad9e8000
read(4, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 414
lseek(4, -249, SEEK_CUR) = 165
read(4, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 249
close(4) = 0
munmap(0x7f67ad9e8000, 4096) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
close(3) = 0
open("/mnt/newlog3.txt", O_RDWR|O_CREAT|O_APPEND, 0666) = 3 ##打开/mnt/newlog3.txt文件:对应脚本第7行
fstat(3, {st_mode=S_IFREG|0644, st_size=438, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=438, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f67ad9e8000
write(3, "2019-02-11 18:41:16 Hello world!"..., 46) = 46 ##写/mnt/newlog3.txt文件:对应脚本第10行
close(3) = 0 ##关闭/mnt/newlog3.txt文件:对应脚本第11行
munmap(0x7f67ad9e8000, 4096) = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f67ad2ac850}, {0x7f67ad54ed38, [], SA_RESTORER, 0x7f67ad2ac850}, 8) = 0
exit_group(0) = ?
从上面分析,shell脚本是边解析边执行,在执行完脚本后,再关闭脚本文件;perl和python脚本是先解析再执行,在执行脚本之前,
已经完成了脚本的解析,直接关闭了脚本文件。
如何控制perl或python脚本在执行脚本时不关闭脚本文件呢?我们需要从perl和python源码着手分析。
perl和python源码分析
python源码分析执行过程
注:以python-2.7.9源码为分析蓝本
/* Main program */ int
Py_Main(int argc, char **argv)
{
......
if (sts==-) {
/* call pending calls like signal handlers (SIGINT) */
if (Py_MakePendingCalls() == -) {
PyErr_Print();
sts = ;
} else {
sts = PyRun_AnyFileExFlags(
fp,
filename == NULL ? "<stdin>" : filename,
filename != NULL, &cf) != ; /* 是否执行python脚本文件作为是否关闭脚本文件的依据 */
}
}
......
}
/* Parse input from a file and execute it */ int
PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit,
PyCompilerFlags *flags)
{
if (filename == NULL)
filename = "???";
if (Py_FdIsInteractive(fp, filename)) { /* 交互式执行python命令 */
int err = PyRun_InteractiveLoopFlags(fp, filename, flags);
if (closeit)
fclose(fp);
return err;
}
else
return PyRun_SimpleFileExFlags(fp, filename, closeit, flags); /* 执行python脚本文件 */
}
PyRun_SimpleFileExFlags调用PyRun_FileExFlags函数:
PyObject *
PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals,
PyObject *locals, int closeit, PyCompilerFlags *flags)
{
PyObject *ret;
mod_ty mod;
PyArena *arena = PyArena_New();
if (arena == NULL)
return NULL;
/* Author: 解析python脚本文件 */
mod = PyParser_ASTFromFile(fp, filename, start, , ,
flags, NULL, arena);
if (closeit)
14 fclose(fp); /* 解析完成后,关闭打开的python脚本文件 */
if (mod == NULL) {
PyArena_Free(arena);
return NULL;
}
ret = run_mod(mod, filename, globals, locals, flags, arena); /* 执行python脚本 */
PyArena_Free(arena);
return ret;
}
从python脚本的执行过程看,当python命令传入的是脚本文件,则先解析python脚本内容,然后关闭打开的脚本文件,最后执行python脚本。
perl源码分析执行过程
注:以perl-5.16.3源码为分析蓝本
#ifdef NO_ENV_ARRAY_IN_MAIN
extern char **environ;
int
main(int argc, char **argv) /* in miniperlmain.c */
#else
int
main(int argc, char **argv, char **env)
#endif
{
......
exitstatus = perl_parse(my_perl, xs_init, argc, argv, (char **)NULL); /* 做perl脚本解析: S_parse_body函数 */
if (!exitstatus) {
perl_run(my_perl); /* 执行perl脚本 */
}
......
} #define parse_body(a,b) S_parse_body(aTHX_ a,b)
/* in perl.c */
int
perl_parse(pTHXx_ XSINIT_t xsinit, int argc, char **argv, char **env)
{
......
switch (ret) {
case :
parse_body(env,xsinit); /* 真正做perl脚本解析的函数是S_parse_body */
......
break;
......
}
STATIC void *
S_parse_body(pTHX_ char **env, XSINIT_t xsinit)
{
......
rsfp = open_script(scriptname, dosearch, &suidscript); /* 打开perl脚本文件 */
if (!rsfp) {
rsfp = PerlIO_stdin();
lex_start_flags = LEX_DONT_CLOSE_RSFP;
} ......
lex_start(linestr_sv, rsfp, lex_start_flags); /* 准备perl解析环境和执行环境,实际函数是 Perl_lex_start */
if(linestr_sv)
SvREFCNT_dec(linestr_sv);
......
/* now parse the script */
SETERRNO(,SS_NORMAL);
/* yyparse函数解析perl脚本文件,然后关闭脚本: 实际调用Perl_lex_next_chunk函数关闭脚本文件 */
if (yyparse(GRAMPROG) || PL_parser->error_count) {
if (PL_minus_c)
Perl_croak(aTHX_ "%s had compilation errors.\n", PL_origfilename);
else {
Perl_croak(aTHX_ "Execution of %s aborted due to compilation errors.\n",
PL_origfilename);
}
}
......
}
从perl脚本的执行过程看,当perl命令传入的是脚本文件,则先解析perl脚本内容,然后关闭打开的脚本文件,最后执行perl脚本。
从python和perl源码分析过程看,两种脚本的执行过程都有一个参数控制着脚本的关闭方式。在python源码中,是PyRun_FileExFlags函数的closeit参数,
当closeit为0是,python脚本执行完成后,不直接关闭打开的python脚本文件。在perl源码中,是Perl_lex_start函数的flags参数,当flags参数包含LEX_DONT_CLOSE_RSFP时,
perl脚本解析完成后不直接关闭打开的perl脚本文件。
源码修改
依据我们的分析,可以修改源码控制python和perl脚本的关闭方式。源码修改方法如下。
python源码修改方式:
int
Py_Main(int argc, char **argv)
{
......
int closeit = , RunAnyFileExFlag = ; /* 定义是否关闭python脚本的变量 */
......
if (sts==-) {
/* call pending calls like signal handlers (SIGINT) */
if (Py_MakePendingCalls() == -) {
fprintf(stderr, "call Py_MakePendingCalls return -1...\n");
PyErr_Print();
sts = ;
} else {
/* closeit decide whether closing python file */
closeit = ;
RunAnyFileExFlag = ;
sts = PyRun_AnyFileExFlags(
fp,
filename == NULL ? "<stdin>" : filename,
closeit /* filename != NULL */, &cf) != ; /* 如果是执行的脚本文件,则不关闭python脚本文件 */
}
}
......
if(RunAnyFileExFlag && !closeit){ /* 在python结束之前关闭已经打开的python脚本文件 */
fclose(fp);
}
#endif
Py_Finalize();
......
}
perl源码修改方式:
STATIC void * S_parse_body(pTHX_ char **env, XSINIT_t xsinit)
/* lex_start中, 添加 LEX_DONT_CLOSE_RSFP 标记 */
lex_start(linestr_sv, rsfp, lex_start_flags | LEX_DONT_CLOSE_RSFP);
/* fprintf(stderr,"lex_start end......\n"); */
if(linestr_sv)
SvREFCNT_dec(linestr_sv); 笔者注: 在perl脚本执行完成后,由PerlIO_destruct函数完成后perl脚本文件的关闭动作!
修改源码后测试结果
perl脚本执行过程:
# strace /root/liangjs/hello.pl
execve("/root/liangjs/hello.pl", ["/root/liangjs/hello.pl"], [/* 34 vars */]) =
....
open("/root/liangjs/hello.pl", O_RDONLY) = ##打开测试perl脚本文件
ioctl(, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7ffe347e36a0) = - ENOTTY (Inappropriate ioctl for device)
lseek(, , SEEK_CUR) =
fcntl(, F_SETFD, FD_CLOEXEC) =
......
read(, "#!/usr/bin/env perl\n\n$datestring"..., ) = ##读取perl脚本文件内容并解析
read(, "", ) = ##没有关闭perl脚本文件
......
open("/etc/localtime", O_RDONLY|O_CLOEXEC) = ##获取时间信息
....
open("/mnt/newlog3.txt", O_WRONLY|O_CREAT|O_APPEND, ) =
lseek(, , SEEK_END) =
ioctl(, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7ffe347e3540) = - ENOTTY (Inappropriate ioctl for device)
lseek(, , SEEK_CUR) =
fstat(, {st_mode=S_IFREG|, st_size=, ...}) =
fcntl(, F_SETFD, FD_CLOEXEC) =
brk() = 0xf88000
brk(0xfaa000) = 0xfaa000
write(, "Wed Feb 20 20:05:18 2019 hello w"..., ) = ##写日志文件/mnt/newlog3.txt
close() = ##关闭日志文件/mnt/newlog3.txt
........
write(, "call PerlIO_destruct......\n", 27call PerlIO_destruct......
) =
close() = ##关闭已经打开的perl脚本文件
exit_group() = ?
+++ exited with +++
python脚本执行过程:
stat("/root/liangjs/py_hello.py", {st_mode=S_IFREG|, st_size=, ...}) =
open("/root/liangjs/py_hello.py", O_RDONLY) =
fstat(, {st_mode=S_IFREG|, st_size=, ...}) =
mmap(NULL, , PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -, ) = 0x7f8830aa9000
fstat(, {st_mode=S_IFREG|, st_size=, ...}) =
lseek(, , SEEK_SET) =
read(, "#!/usr/bin/env python\n\nimport os"..., ) =
read(, "t/newlog3.txt\", 0644)\n", ) =
close() = ##第一次打开python脚本文件后关闭!!!
munmap(0x7f8830aa9000, ) =
stat("/root/liangjs/py_hello.py", {st_mode=S_IFREG|, st_size=, ...}) =
write(, "second open python script file.."..., 34second open python script file...
) =
open("/root/liangjs/py_hello.py", O_RDONLY) =
fstat(, {st_mode=S_IFREG|, st_size=, ...}) =
write(, "call PyRun_AnyFileExFlags...\n", 29call PyRun_AnyFileExFlags...
) =
ioctl(, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7ffd9da9be30) = - ENOTTY (Inappropriate ioctl for device)
brk() = 0x1a9e000
brk(0x1ac0000) = 0x1ac0000
fstat(, {st_mode=S_IFREG|, st_size=, ...}) =
mmap(NULL, , PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -, ) = 0x7f8830aa9000
read(, "#!/usr/bin/env python\n\nimport os"..., ) =
stat("/etc/sysconfig/64bit_strstr_via_64bit_strstr_sse2_unaligned", 0x7ffd9da9bb10) = - ENOENT (No such file or directory)
read(, "", ) = ##第二次打开python脚本文件后没有关闭动作!!!
.....
write(, "close python file, RunAnyFileExF"..., 53close python file, RunAnyFileExFlag = , closeit =
) =
close() = ##最后关闭打开的python脚本文件
munmap(0x7f8830aa9000, ) =
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f8830743370}, {0x4fe640, [], SA_RESTORER, 0x7f8830743370}, ) =
exit_group() = ?
+++ exited with +++
修改python和perl源码后,从以上执行过程来看,都是在执行完python和perl脚本之后才关闭相应的脚本文件。
说明这种修改方式符合我们控制perl和python脚本文件关闭时刻的预期!
进一步的工作
默认动作还是解析完perl和python脚本后,直接关闭脚本文件;可以添加脚本执行参数,控制脚本文件解析完成后是否关闭。
相关议题
在perl较低版本中,例如perl-5.10.0版本,yy_parser结构体中没有lex_flags成员,所以要实现控制脚本文件关闭,需要添加相应的成员和控制流程。
Perl-5.10.0版本源码修改
parser.h文件
typedef struct yy_parser { /* parser state */ struct yy_parser *old_parser; /* previous value of PL_parser */
......
char tokenbuf[];
/* 2018-11-14, with no close file */
U8 lex_flags;
} yy_parser;
toke.c文件:
void
Perl_lex_start(pTHX_ SV *line, PerlIO *rsfp, bool new_filter)
{
......
parser->copline = NOLINE;
parser->lex_state = LEX_NORMAL;
parser->expect = XSTATE;
parser->rsfp = rsfp;
parser->rsfp_filters = (new_filter || !oparser) ? newAV()
: (AV*)SvREFCNT_inc(oparser->rsfp_filters);
/* add 2018-11-14, for no closefile */
parser->lex_flags = LEX_DONT_CLOSE_RSFP; Newx(parser->lex_brackstack, , char);
Newx(parser->lex_casestack, , char);
*parser->lex_casestack = '\0';
......
}
/* delete a parser object */ void
Perl_parser_free(pTHX_ const yy_parser *parser)
{
PL_curcop = parser->saved_curcop;
SvREFCNT_dec(parser->linestr); /* modi 2018-11-14, with no close file */
if ( parser->rsfp == PerlIO_stdin() || (parser->lex_flags & LEX_DONT_CLOSE_RSFP) )
PerlIO_clearerr(parser->rsfp);
else if (parser->rsfp && parser->old_parser
&& parser->rsfp != parser->old_parser->rsfp)
PerlIO_close(parser->rsfp);
SvREFCNT_dec(parser->rsfp_filters); Safefree(parser->stack);
Safefree(parser->lex_brackstack);
Safefree(parser->lex_casestack);
PL_parser = parser->old_parser;
Safefree(parser);
}
STATIC char *
S_skipspace(pTHX_ register char *s)
{
...... if (PL_preprocess && !PL_in_eval)
(void)PerlProc_pclose(PL_rsfp);
else if ((PerlIO*)PL_rsfp == PerlIO_stdin() || (PL_parser->lex_flags & LEX_DONT_CLOSE_RSFP) )
/* modi 2018-11-14, with no close file */
PerlIO_clearerr(PL_rsfp);
else
(void)PerlIO_close(PL_rsfp);
PL_rsfp = NULL;
return s;
} /* not at end of file, so we only read another line */
/* make corresponding updates to old pointers, for yyerror() */
oldprevlen = PL_oldbufptr - PL_bufend
......
} }
int
Perl_yylex(pTHX)
{
......
do {
bof = PL_rsfp ? TRUE : FALSE;
if ((s = filter_gets(PL_linestr, PL_rsfp, )) == NULL) {
fake_eof:
#ifdef PERL_MAD
PL_realtokenstart = -;
#endif
if (PL_rsfp) {
if (PL_preprocess && !PL_in_eval)
(void)PerlProc_pclose(PL_rsfp);
else if ((PerlIO *)PL_rsfp == PerlIO_stdin() || (PL_parser->lex_flags & LEX_DONT_CLOSE_RSFP) )
/* modi 2018-11-14, with no close */
PerlIO_clearerr(PL_rsfp);
else
(void)PerlIO_close(PL_rsfp);
PL_rsfp = NULL;
PL_doextract = FALSE;
}
...... }
PS:您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【原创】控制perl和python脚本执行过程中脚本文件是否关闭的方法的更多相关文章
-
android模拟器(genymotion)+appium+python 框架执行过程中问题解答
1.case运行过程中中文输入不进去? 答:注意事项 1)需要修改系统编码为utf-8,才能解决中文输入问题,case执行入口文件添加代码如下: import sys reload(sys) sys. ...
-
Linux系统在启动过程中内核文件丢失的解决方法
在/boot目录下有两个重要的文件,分别是: vmlinuz-3.10.0-123.el7.x86_64 内核文件 initamfs-3.10.0-123.el7.x86_64.img ...
-
shell脚本编程之变量简介及脚本执行过程
脚本变量简介 变量类型:字符型.数值型.真.假:事先确定数据的存放格式和长度: 变量存放在内存空间: 编译型语言,没有额外的处理逻辑,属于强类型语言: 脚本型语言,可以有解释器控制:所以,可以是弱类型 ...
-
Linux脚本执行过程重定向
Linux脚本执行过程重定向 一.bash调试脚本,并将执行过程重定向到指定文件 bash –x shell.sh 2>&1 | tee shell.log
-
通过DT10获取程序执行过程中的实时覆盖率
DT10是新一代的动态测试工具,可以长时间跟踪记录目标程序执行情况,获取目标程序动态执行数据,帮助进行难于重现的Bug错误分析,覆盖率检测,性能测试,变量跟踪等等功能. 系统测试覆盖率,通常是用于判断 ...
-
SQL SERVER 2008:内部查询处理器错误: 查询处理器在执行过程中遇到意外错误
今天一个同事突然告诉我,以前跑得很正常的一个SQL语句,执行时突然报如下错误: 消息1222,级别16,状态18,第1 行 已超过了锁请求超时时段. ...
-
Deepin下phpunit安装,以及执行过程中所遇到的问题
Deepin下phpunit安装,以及执行过程中所遇到的问题 安装phpunit步骤 wget https://phar.phpunit.de/phpunit.phar chmod +x phpuni ...
-
Selenium2学习-018-WebUI自动化实战实例-016-自动化脚本编写过程中的登录验证码问题
日常的 Web 网站开发的过程中,为提升登录安全或防止用户通过脚本进行黄牛操作(宇宙最贵铁皮天朝魔都的机动车牌照竞拍中),很多网站在登录的时候,添加了验证码验证,而且验证码的实现越来越复杂,对其进行脚 ...
-
python顺序执行多个py文件
python顺序执行多个py文件 假如我要执行code目录下的python程序,假设该目录下有1.py,2.py,3.py,4.py四个文件,但是我想执行1.py,2.py,4.py,则可在该目录下创 ...
随机推荐
-
iOS -Swift 3.0 -UIButton属性大全
// // ViewController.swift // Swift-UIButton // // Created by luorende on 16/9/9. // Copyright © ...
-
c/c++笔记
string 若要根据字典序比较string类型的大小,只需要用><=就可以啦 例如: string s1="abcz"; string s2="abcd&q ...
-
[转]eoe社区cocos2d-x游戏引擎知识大汇总
[eoeAndroid 社区]特意为大家汇总了cocos2d-x知识贴,分量十足,纯正干或.从基础教程到游戏应用的开发,我们不让知识流失,我们要做知识的搬运工还有加工 师.希望大家能够一起的学习,和大 ...
-
STL——空间的配置和释放std::alloc(第一级配置器和第二级配置器)
1 空间的配置和释放,std::alloc 对象构造前的空间配置和对象析构后的空间释放,由<stl_alloc.h>负责,SGI对此的设计哲学如下: 向system heap要求空间 考虑 ...
-
Jquery Offset, Document, Window 都是什么
From http://www.cnblogs.com/luhe/archive/2012/11/14/2769263.html JQuery Offset实验与应用 我们有时候需要实现这样一种功 ...
-
禁用事件event默认行为
在大多数情况下,为事件处理函数返回false,可以防止默认的事件行为.例如,默认情况下点击一个<a>元素,页面会跳转到该元素href属性指定的页. js中return false作用一般是 ...
-
【朝花夕拾】Android性能篇之(四)Apk打包
前言 APK,即Android Package,是将android程序和资源整合在一起,形成的一个.apk文件.相信所有的Android程序员是在IDE的帮助下,完成打包轻而易举,但对打包流程真正清楚 ...
-
Angular6封装LED时钟数字组件
一.运行截图 截图1: 截图2: 二.代码 html代码: <div class="time" > <ng-container #container> &l ...
-
P1879 [USACO06NOV]玉米田Corn Fields 状压dp/插头dp
正解:状压dp/插头dp 解题报告: 链接! ……我真的太菜了……我以为一个小时前要搞完的题目调错误调了一个小时……90分到100我差不多搞了一个小时…… 然后这题还是做过的……就很气,觉得确实是要搞 ...
-
static 继承
静态方法大家应该都比较熟悉,在这里主要谈一下静态方法在继承时的一些注意事项. 1.父类方法如果是静态方法,子类不能覆盖为非静态方法: 2.父类方法如果是非静态方法,子类不能覆盖为静态方法: 3.父类静 ...