Shell脚本调试技术

shell脚本的基础知识(创建、执行、调试) shell脚本的基础知识一、shell脚本的意义二、如何创建shell脚本三、如何执行shell脚本 一、shell脚本的意义 1、shell:脚本中命令的解释器 2、脚本的意义: 记录命令执行的过程和执行逻辑,以便以后重复执行 脚本可以批量处理主机 脚本可以定时处理主机 二、如何创建shell脚本 #!/bin/bash ##幻数 1、编辑子配置文件~/.vimrc,自动添加说明 当新建立的文件以.sh或.script结尾时,调用Skk函数,注意函数名必须以大写字母开头,否则会报错 call:调用 阅读详情
 
曹 羽中 ( caoyuz@cn.ibm.com), 软件工程师, IBM中国开发中心
曹羽中,在北京航空航天大学获得计算机软件与理论专业的硕士学位,具有数年的 unix 环境下的 C 语言,Java,数据库以及电信计费软件的开发经验,他的技术兴趣还包括 OSGi 和搜索技术。他目前在IBM中国系统与科技实验室从事系统管理软件的开发工作,可以通过 caoyuz@cn.ibm.com与他联系。

简介: 本文全面系统地介绍了shell脚本调试技术,包括使用echo, tee, trap等命令输出关键信息,跟踪变量的值,在脚本中植入调试钩子,使用“-n”选项进行shell脚本的语法检查, 使用“-x”选项实现shell脚本逐条语句的跟踪,巧妙地利用shell的内置变量增强“-x”选项的输出信息等

shell编程在unix/linux世界中使用得非常广泛,熟练掌握shell编程也是成为一名优秀的unix/linux开发者和系统管理员的必经之路。脚本调试的主要工作就是发现引发脚本错误的原因以及在脚本源代码中定位发生错误的行,常用的手段包括分析输出的错误信息,通过在脚本中加入调试语句,输出调试信息来辅助诊断错误,利用调试工具等。但与其它高级语言相比,shell解释器缺乏相应的调试机制和调试工具的支持,其输出的错误信息又往往很不明确,初学者在调试脚本时,除了知道用echo语句输出一些信息外,别无它法,而仅仅依赖于大量的加入echo语句来诊断错误,确实令人不胜其繁,故常见初学者抱怨shell脚本太难调试了。本文将系统地介绍一些重要的shell脚本调试技术,希望能对shell的初学者有所裨益。

本文的目标读者是unix/linux环境下的开发人员,测试人员和系统管理员,要求读者具有基本的shell编程知识。本文所使用范例在Bash3.1+Redhat Enterprise Server 4.0下测试通过,但所述调试技巧应也同样适用于其它shell。

二. 在shell脚本中输出调试信息

通过在程序中加入调试语句把一些关键地方或出错的地方的相关信息显示出来是最常见的调试手段。Shell程序员通常使用echo(ksh程序员常使用print)语句输出信息,但仅仅依赖echo语句的输出跟踪信息很麻烦,调试阶段在脚本中加入的大量的echo语句在产品交付时还得再费力一一删除。针对这个问题,本节主要介绍一些如何方便有效的输出调试信息的方法。

1. 使用trap命令

trap命令用于捕获指定的信号并执行预定义的命令。
其基本的语法是:
trap 'command' signal
其中signal是要捕获的信号,command是捕获到指定的信号之后,所要执行的命令。可以用kill –l命令看到系统中全部可用的信号名,捕获信号后所执行的命令可以是任何一条或多条合法的shell语句,也可以是一个函数名。
shell脚本在执行时,会产生三个所谓的“伪信号”,(之所以称之为“伪信号”是因为这三个信号是由shell产生的,而其它的信号是由操作系统产生的),通过使用trap命令捕获这三个“伪信号”并输出相关信息对调试非常有帮助。


表 1. shell伪信号
信号名何时产生
EXIT从一个函数中退出或整个脚本执行完毕
ERR当一条命令返回非零状态时(代表命令执行不成功)
DEBUG脚本中每一条命令执行之前

通过捕获EXIT信号,我们可以在shell脚本中止执行或从函数中退出时,输出某些想要跟踪的变量的值,并由此来判断脚本的执行状态以及出错原因,其使用方法是:
trap 'command' EXIT 或 trap 'command' 0

通过捕获ERR信号,我们可以方便的追踪执行不成功的命令或函数,并输出相关的调试信息,以下是一个捕获ERR信号的示例程序,其中的$LINENO是一个shell的内置变量,代表shell脚本的当前行号。

$ cat -n exp1.sh      
1  ERRTRAP()      
2  {      
3    echo "[LINE:$1] Error: Command or function exited with status $?"      
4  }      
5  foo()      
6  {      
7    return 1;      
8  }      
9  trap 'ERRTRAP $LINENO' ERR     
10  abc     
11  foo       

其输出结果如下:

$ sh exp1.shexp1.sh: line 10: abc: command not found[LINE:10] Error: Command or function exited with status 127[LINE:11] Error: Command or function exited with status 1       

在调试过程中,为了跟踪某些变量的值,我们常常需要在shell脚本的许多地方插入相同的echo语句来打印相关变量的值,这种做法显得烦琐而笨拙。而通过捕获DEBUG信号,我们只需要一条trap语句就可以完成对相关变量的全程跟踪。

以下是一个通过捕获DEBUG信号来跟踪变量的示例程序:

$ cat –n exp2.sh     1  #!/bin/bash     2  trap 'echo “before execute line:$LINENO, a=$a,b=$b,c=$c”' DEBUG     3  a=1     4  if [ "$a" -eq 1 ]     5  then     6     b=2     7  else     8     b=1     9  fi    10  c=3    11  echo "end" 

其输出结果如下:

$ sh exp2.shbefore execute line:3, a=,b=,c=before execute line:4, a=1,b=,c=before execute line:6, a=1,b=,c=before execute line:10, a=1,b=2,c=before execute line:11, a=1,b=2,c=3end 

从运行结果中可以清晰的看到每执行一条命令之后,相关变量的值的变化。同时,从运行结果中打印出来的行号来分析,可以看到整个脚本的执行轨迹,能够判断出哪些条件分支执行了,哪些条件分支没有执行。

2. 使用tee命令

在shell脚本中管道以及输入输出重定向使用得非常多,在管道的作用下,一些命令的执行结果直接成为了下一条命令的输入。如果我们发现由管道连接起来的一批命令的执行结果并非如预期的那样,就需要逐步检查各条命令的执行结果来判断问题出在哪儿,但因为使用了管道,这些中间结果并不会显示在屏幕上,给调试带来了困难,此时我们就可以借助于tee命令了。

tee命令会从标准输入读取数据,将其内容输出到标准输出设备,同时又可将内容保存成文件。例如有如下的脚本片段,其作用是获取本机的ip地址:

ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1'| cut -d : -f3 | awk '{print $1}'` #注意=号后面的整句是用反引号(数字1键的左边那个键)括起来的。echo $ipaddr 

运行这个脚本,实际输出的却不是本机的ip地址,而是广播地址,这时我们可以借助tee命令,输出某些中间结果,将上述脚本片段修改为:

ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1'| tee temp.txt | cut -d : -f3 | awk '{print $1}'`echo $ipaddr 

之后,将这段脚本再执行一遍,然后查看temp.txt文件的内容:

$ cat temp.txtinet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0 

我们可以发现中间结果的第二列(列之间以:号分隔)才包含了IP地址,而在上面的脚本中使用cut命令截取了第三列,故我们只需将脚本中的cut -d : -f3改为cut -d : -f2即可得到正确的结果。

具体到上述的script例子,我们也许并不需要tee命令的帮助,比如我们可以分段执行由管道连接起来的各条命令并查看各命令的输出结果来诊断错误,但在一些复杂的shell脚本中,这些由管道连接起来的命令可能又依赖于脚本中定义的一些其它变量,这时我们想要在提示符下来分段运行各条命令就会非常麻烦了,简单地在管道之间插入一条tee命令来查看中间结果会更方便一些。

3. 使用"调试钩子"

在C语言程序中,我们经常使用DEBUG宏来控制是否要输出调试信息,在shell脚本中我们同样可以使用这样的机制,如下列代码所示:

if [ “$DEBUG” = “true” ]; thenecho “debugging”  #此处可以输出调试信息fi 

这样的代码块通常称之为“调试钩子”或“调试块”。在调试钩子内部可以输出任何您想输出的调试信息,使用调试钩子的好处是它是可以通过DEBUG变量来控制的,在脚本的开发调试阶段,可以先执行export DEBUG=true命令打开调试钩子,使其输出调试信息,而在把脚本交付使用时,也无需再费事把脚本中的调试语句一一删除。

如果在每一处需要输出调试信息的地方均使用if语句来判断DEBUG变量的值,还是显得比较繁琐,通过定义一个DEBUG函数可以使植入调试钩子的过程更简洁方便,如下面代码所示:

$ cat –n exp3.sh     1  DEBUG()     2  {     3  if [ "$DEBUG" = "true" ]; then     4      $@       5  fi     6  }     7  a=1     8  DEBUG echo "a=$a"     9  if [ "$a" -eq 1 ]    10  then    11       b=2    12  else    13       b=1    14  fi    15  DEBUG echo "b=$b"    16  c=3    17  DEBUG echo "c=$c" 

在上面所示的DEBUG函数中,会执行任何传给它的命令,并且这个执行过程是可以通过DEBUG变量的值来控制的,我们可以把所有跟调试有关的命令都作为DEBUG函数的参数来调用,非常的方便。


回页首

三. 使用shell的执行选项

上一节所述的调试手段是通过修改shell脚本的源代码,令其输出相关的调试信息来定位错误的,那有没有不修改源代码来调试shell脚本的方法呢?答案就是使用shell的执行选项,本节将介绍一些常用选项的用法:

-n 只读取shell脚本,但不实际执行
-x 进入跟踪方式,显示所执行的每一条命令
-c "string" 从strings中读取命令

“-n”可用于测试shell脚本是否存在语法错误,但不会实际执行命令。在shell脚本编写完成之后,实际执行之前,首先使用“-n”选项来测试脚本是否存在语法错误是一个很好的习惯。因为某些shell脚本在执行时会对系统环境产生影响,比如生成或移动文件等,如果在实际执行才发现语法错误,您不得不手工做一些系统环境的恢复工作才能继续测试这个脚本。

“-c”选项使shell解释器从一个字符串中而不是从一个文件中读取并执行shell命令。当需要临时测试一小段脚本的执行结果时,可以使用这个选项,如下所示:
sh -c 'a=1;b=2;let c=$a+$b;echo "c=$c"'

"-x"选项可用来跟踪脚本的执行,是调试shell脚本的强有力工具。“-x”选项使shell在执行脚本的过程中把它实际执行的每一个命令行显示出来,并且在行首显示一个"+"号。 "+"号后面显示的是经过了变量替换之后的命令行的内容,有助于分析实际执行的是什么命令。 “-x”选项使用起来简单方便,可以轻松对付大多数的shell调试任务,应把其当作首选的调试手段。

如果把本文前面所述的trap ‘command’ DEBUG机制与“-x”选项结合起来,我们就可以既输出实际执行的每一条命令,又逐行跟踪相关变量的值,对调试相当有帮助。

仍以前面所述的exp2.sh为例,现在加上“-x”选项来执行它:

$ sh –x exp2.sh+ trap 'echo "before execute line:$LINENO, a=$a,b=$b,c=$c"' DEBUG++ echo 'before execute line:3, a=,b=,c='before execute line:3, a=,b=,c=+ a=1++ echo 'before execute line:4, a=1,b=,c='before execute line:4, a=1,b=,c=+ '[' 1 -eq 1 ']'++ echo 'before execute line:6, a=1,b=,c='before execute line:6, a=1,b=,c=+ b=2++ echo 'before execute line:10, a=1,b=2,c='before execute line:10, a=1,b=2,c=+ c=3++ echo 'before execute line:11, a=1,b=2,c=3'before execute line:11, a=1,b=2,c=3+ echo endend 

在上面的结果中,前面有“+”号的行是shell脚本实际执行的命令,前面有“++”号的行是执行trap机制中指定的命令,其它的行则是输出信息。

shell的执行选项除了可以在启动shell时指定外,亦可在脚本中用set命令来指定。 "set -参数"表示启用某选项,"set +参数"表示关闭某选项。有时候我们并不需要在启动时用"-x"选项来跟踪所有的命令行,这时我们可以在脚本中使用set命令,如以下脚本片段所示:

set -x    #启动"-x"选项 要跟踪的程序段 set +x     #关闭"-x"选项 

set命令同样可以使用上一节中介绍的调试钩子—DEBUG函数来调用,这样可以避免脚本交付使用时删除这些调试语句的麻烦,如以下脚本片段所示:

DEBUG set -x    #启动"-x"选项 要跟踪的程序段 DEBUG set +x    #关闭"-x"选项 


回页首

四. 对"-x"选项的增强

"-x"执行选项是目前最常用的跟踪和调试shell脚本的手段,但其输出的调试信息仅限于进行变量替换之后的每一条实际执行的命令以及行首的一个"+"号提示符,居然连行号这样的重要信息都没有,对于复杂的shell脚本的调试来说,还是非常的不方便。幸运的是,我们可以巧妙地利用shell内置的一些环境变量来增强"-x"选项的输出信息,下面先介绍几个shell内置的环境变量:

$LINENO
代表shell脚本的当前行号,类似于C语言中的内置宏__LINE__

$FUNCNAME
函数的名字,类似于C语言中的内置宏__func__,但宏__func__只能代表当前所在的函数名,而$FUNCNAME的功能更强大,它是一个数组变量,其中包含了整个调用链上所有的函数的名字,故变量${FUNCNAME[0]}代表shell脚本当前正在执行的函数的名字,而变量${FUNCNAME[1]}则代表调用函数${FUNCNAME[0]}的函数的名字,余者可以依此类推。

$PS4
主提示符变量$PS1和第二级提示符变量$PS2比较常见,但很少有人注意到第四级提示符变量$PS4的作用。我们知道使用“-x”执行选项将会显示shell脚本中每一条实际执行过的命令,而$PS4的值将被显示在“-x”选项输出的每一条命令的前面。在Bash Shell中,缺省的$PS4的值是"+"号。(现在知道为什么使用"-x"选项时,输出的命令前面有一个"+"号了吧?)。

利用$PS4这一特性,通过使用一些内置变量来重定义$PS4的值,我们就可以增强"-x"选项的输出信息。例如先执行export PS4='+{$LINENO:${FUNCNAME[0]}} ', 然后再使用“-x”选项来执行脚本,就能在每一条实际执行的命令前面显示其行号以及所属的函数名。

以下是一个存在bug的shell脚本的示例,本文将用此脚本来示范如何用“-n”以及增强的“-x”执行选项来调试shell脚本。这个脚本中定义了一个函数isRoot(),用于判断当前用户是不是root用户,如果不是,则中止脚本的执行

$ cat –n exp4.sh     1  #!/bin/bash     2  isRoot()     3  {     4          if [ "$UID" -ne 0 ]     5                  return 1     6          else     7                  return 0     8          fi     9  }    10  isRoot    11  if ["$?" -ne 0 ]    12  then    13          echo "Must be root to run this script"    14          exit 1    15  else    16          echo "welcome root user"    17          #do something    18  fi 

首先执行sh –n exp4.sh来进行语法检查,输出如下:

$ sh –n exp4.shexp4.sh: line 6: syntax error near unexpected token `else'exp4.sh: line 6: `      else' 

发现了一个语法错误,通过仔细检查第6行前后的命令,我们发现是第4行的if语句缺少then关键字引起的(写惯了C程序的人很容易犯这个错误)。我们可以把第4行修改为if [ "$UID" -ne 0 ]; then来修正这个错误。再次运行sh –n exp4.sh来进行语法检查,没有再报告错误。接下来就可以实际执行这个脚本了,执行结果如下:

$ sh exp4.shexp2.sh: line 11: [1: command not foundwelcome root user 

尽管脚本没有语法错误了,在执行时却又报告了错误。错误信息还非常奇怪“[1: command not found”。现在我们可以试试定制$PS4的值,并使用“-x”选项来跟踪:

$ export PS4='+{$LINENO:${FUNCNAME[0]}} '$ sh –x exp4.sh+{10:} isRoot+{4:isRoot} '[' 503 -ne 0 ']'+{5:isRoot} return 1+{11:} '[1' -ne 0 ']'exp4.sh: line 11: [1: command not found+{16:} echo 'welcome root user'welcome root user 

从输出结果中,我们可以看到脚本实际被执行的语句,该语句的行号以及所属的函数名也被打印出来,从中可以清楚的分析出脚本的执行轨迹以及所调用的函数的内部执行情况。由于执行时是第11行报错,这是一个if语句,我们对比分析一下同为if语句的第4行的跟踪结果:

+{4:isRoot} '[' 503 -ne 0 ']'+{11:} '[1' -ne 0 ']' 

可知由于第11行的[号后面缺少了一个空格,导致[号与紧挨它的变量$?的值1被shell解释器看作了一个整体,并试着把这个整体视为一个命令来执行,故有“[1: command not found”这样的错误提示。只需在[号后面插入一个空格就一切正常了。

shell中还有其它一些对调试有帮助的内置变量,比如在Bash Shell中还有BASH_SOURCE, BASH_SUBSHELL等一批对调试有帮助的内置变量,您可以通过man sh或man bash来查看,然后根据您的调试目的,使用这些内置变量来定制$PS4,从而达到增强“-x”选项的输出信息的目的。


回页首

五. 总结

现在让我们来总结一下调试shell脚本的过程:
首先使用“-n”选项检查语法错误,然后使用“-x”选项跟踪脚本的执行,使用“-x”选项之前,别忘了先定制PS4变量的值来增强“-x”选项的输出信息,至少应该令其输出行号信息(先执行export PS4='+[$LINENO]',更一劳永逸的办法是将这条语句加到您用户主目录的.bash_profile文件中去),这将使你的调试之旅更轻松。也可以利用trap,调试钩子等手段输出关键调试信息,快速缩小排查错误的范围,并在脚本中使用“set -x”及“set +x”对某些代码块进行重点跟踪。这样多种手段齐下,相信您已经可以比较轻松地抓出您的shell脚本中的臭虫了。如果您的脚本足够复杂,还需要更强的调试能力,可以使用shell调试器bashdb,这是一个类似于GDB的调试工具,可以完成对shell脚本的断点设置,单步执行,变量观察等许多功能,使用bashdb对阅读和理解复杂的shell脚本也会大有裨益。关于bashdb的安装和使用,不属于本文范围,您可参阅http://bashdb.sourceforge.net/上的文档并下载试用。


参考资料



光储微电网混合储能系统的控制策略 随着社会生产力的不断提高,对不可再生资源的大量消耗,人们已经意识到发展可再生能源的重要性,因此微电网技术作为再生能源利用的有效形式被快速发展。蓄电池容量无限大是传统光储微电网混合储能系统控制策略一种理想形式,但实际上蓄电池的容量是有限度的,传统控制策略在蓄电池剩余电量达到阖值时将无法正常使用,由此提出了光储微电网混合储能系统的新型控制策略,又结合实际情况,对开关进行了改进,利用开关与二极管并联,使其拥有四种工作状态,当储能元件剩余电量达到阈值时,可自动恢复电量降低成本,提高并输出电池电能质量。 阅读详情

相关推荐

PLC1200使用CB1241RS485通讯模块做从站进行Modbus Rtu通信

添加新设备(PLC)->设备和网络管理->点击PLC->看到硬件目录选择通信板->点到点->CB1241(RS485)->看到6ES7241-1CH30-1XB0选择添加,如图。指向Modbus保持寄存器数据块的指针 我这里指向了自定义的DB块数据中一个INT数组。在通信->通信处理模块->MODBUS(选择不带RTU的通信指令块)注意:接线时,TRA接485调试模块的B- TRB接调试模块的A+组态后的硬件标识符 270 对应自己组态后自动生成的。1:事务完成,且无任何错误。波特率对应自己使用的。

swmyaopeng的博客 2万+

错误crontab: "/bin/vi" exited with status 127

crontab: "/bin/vi" exited with status 127

dinux的博客 5934

Zabbix 7.0 从入门到精通部署手册

zabbix 入门到精通

weixin_43806846的博客 1028

个人使用verdi技巧(持续更新)

个人使用verdi技巧(持续更新) 1.找到Verdi的signal list 方便查看信号 方法:打开上面菜单栏的window,然后打开signal_list的开关,然后就可以方便的查看信号。

sunshinelifes的博客 4139

告别手动输入!用Burp插件+ddddocr,5分钟搞定图片验证码自动识别

本文详细介绍了如何利用Burp插件和ddddocr开源库快速构建图片验证码自动识别系统,实现高效、零成本的验证码自动化解决方案。通过环境搭建、性能调优和Burp Suite深度集成,显著提升安全测试效率,特别适用于金融和电商系统的批量测试场景。

weixin_29099217的博客 202

具身智能数据采集的工程化指南:从时间同步到质量校验

具身智能的模型训练离不开高质量的多模态轨迹数据,而数据采集并非简单的传感器记录。真实场景中,相机图像、机械臂关节状态与力觉信息必须在时间轴上精确对齐,标定的漂移和格式混乱会让看似正常的数据无法用于训练。时间同步与标定一致性,是决定数据质量的核心技术环节。在机器人抓取、操作等工程应用中,一套包含多传感器同步、轻量记录脚本、自动化质量校验与版本管理的数据采集流程,能大幅降低数据生产的失败率。本文从工程视角拆解具身数据采集中的典型问题,并给出可落地的流程设计与校验方法,帮助团队构建可持续迭代的高质量数据集。

weixin_30603633的博客 510

Linux Trap 命令由来原理用法示例

`trap` 是一个用于**设置或清除信号**处理程序的 Linux 命令。在 Linux 系统中,进程可以通过发送信号给其他进程来通知其发生了某些事件。使用 `trap` 命令可以捕获并处理这些信号,以便在特定条件下执行一些操作。

wang2leee的博客 1470

chipseeker Y叔

这一次讲解非常重要的peak注释,注释在ChIPseeker里只需要用到一个函数annotatePeak,它可以满足大家各方面的需求。 输入 当然需要我们上次讲到的BED文件,ChIPseeker自带了5个BED文件,用getSampleFiles()可以拿到文件的全路径,它返回的是个named list,我这里取第4个文件来演示。annotatePeak的输入也可以是GRanges对象,你如果用R做peak calling的话,直接就可以衔接上ChIPseeker了。 require(ChIPseeke

生信小博士的博客 1589

AI自动化研究失控风险与安全管控机制探讨

人工智能自动化研究正从工具辅助阶段迈向自主迭代阶段,这一转变带来了研发效率的质变。其核心原理在于系统能够自主进行算法生成、实验设计和知识整合,突破了人类认知速度的限制。这种自动化研究的技术价值在于大幅提升研发效率,但同时也带来了技术债指数级累积和系统边界失控的风险。在应用场景中,AI实验室需要建立安全缓冲区,通过价值对齐验证和副作用评估等手动检查点来确保系统可控。当前1200名AI从业者联署呼吁国际协调机制,正是为了在自动化研究与系统安全之间找到平衡点,推动建立标准化的黑匣子记录和验证框架,实现从追求极限速

weixin_33778544的博客 490

ransac拟合2D圆(三点定圆 c++详细版)

RANSAC(Random Sample Consensus,随机采样一致性)算法是一种基于随机采样的迭代算法,主要用于从一组包含大量噪声和异常值(外点)的数据中估计数学模型的参数。

twnkie的博客 1047

置顶必读(2) |《YOLOv8实战:从入门到深度优化》总目录导航 & 学习路线指南(持续更新中)

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》 专栏。该专栏系统复现并梳理全网各类 YOLOv8 改进与实战案例(当前已覆盖分类 / 检测 / 分割 / 追踪 / 关键点 / OBB 检测等方向),坚持持续更新 + 深度解析,质量分长期稳定在 97 分以上,可视为当前市面上 覆盖较全、更新较快、实战导向极强 的 YOLO 改进系列内容之一。

**My Coding Family** 28万+

Shell脚本的调试技术

编程中必不可少的一点就是调试,Shell脚本以其强大的功能令人向往,当然,它的强大之处不只是体现在语言的实现功能上,更强大的是它的调试功能,下面,我将以实例讲解Shell脚本的调试技术。下面是我所用到的实例:#!/bin/bash LINE="Tests run: 196, Failures: 1, Errors: 1" error=`echo $LINE|cut -d':' -f4` ec

张勤一 2349

新系统申请软件著作权详细操作说明

今年八月底版权中心系统升级,新系统相对好用一些,至少不用再拿IE访问了,但是多了一项实名认证。下面介绍新系统的操作流程。 目录注册、登录和实名认证注册登录实名认证软件登记申请申请表填写鉴别材料身份证明文件权利归属证明文件其他材料提交材料变更登记 注册、登录和实名认证 首先访问版权中心系统:https://register.ccopyright.com.cn/login.html,如果老系统有账号直接登录即可,没有的话需要注册。 注册 点击注册按钮进入注册。 根据实际情况选择个人或单位,每个个人或单位只能在

Programming Talk 1万+
上一篇: 使用trap/tee命令/调试钩子调试Shell脚本
下一篇: linux在多核处理器上的负载均衡原理
gracioushe
博客等级 码龄25年 62粉丝 98原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值