• Linux Shell 笔记


    1、查看进程的环境变量

    普通:$cat /proc/1642/environ 
    换行:$cat /proc/1642/environ | tr '' ' '
    tr的命令格式是tr SET1 SET2,凡是在SET1中的字符,都会被替换为SET2中相应位置上的字符。

    2、SHELL脚本赋值与等于判断

    赋值:$var=value
    相等:$var  = value
    在赋值时不要留有空格。

    3、从进程名字得知进程ID

    $ pgrep my_proc 

    4、当前环境变量

    $PATH
    记住必须是大写
    输出BASH路径:$echo $SHELL
    注意不要在*.sh文件里定义名为PATH的变量,否则会导致后面的命令无法执行,因为PATH被更换掉了。
    修改环境变量:
    export PATH=/home/work/cswuyg/:$PATH
    export命令可以打印出所有的环境变量信息

    5、查看文件

    alias ll='ls -l' ; ll等同于ls -l
    查看隐藏文件:
    隐藏属性的文件的文件名以“点”开头
    ls -al 
    查看普通文件:
    ls -l
    按时间排序:
    ll -t;   ll -rt (时间从小到大)
    查看文件名含有某些字符的文件:
    ll *active*03-24*.origin -rt
    按文件大小排序:
    ls -l |sort -n  

    6、bash中的双引号和单引号的不同

    shell脚本:
    count=9              
    fruit=apple          
    echo "we hava $count${fruit}s"     
    其中fruit是字符串变量, 如果双引号换成单引号那就导致fruit输出错误。
    加上大括号{}是因为后面有其他字符串,需要做隔开。
    shell中的单引号、双引号、反引号:
    单引号:所有转义符全部关闭,完整的反应括号中的内容
    双引号:部分转义符关闭,但某些则保留(如:$ )
    反引号:反引号内作为一个系统命令并执行

    7、shell脚本中的括号

    两层小括号
    ((exp)),两层括号表明里面的是整数型运算,如:
    - a=10;((a++));echo $a   
    - for ((i=0;i<5;i++));do echo $i;done  
    中括号
    中括号等同于test;也可以用来引用数组元素。
    - test功能举例:
      a=10;if [ $a = '10' ];then echo 'a==10';fi 
    - 数组元素引用举例:
      array[1]=world
      array[0]=hello
      for k in ${!array[@]};do echo ${array[${k}]};done
    双中括号[[]]也有test的功能,而且比单个中括号更通用。
    大括号
    可以:扩展;代码块;替换;匹配;取字符
     - 扩展举例:
      touch {a,b}.txt : 创建a.txt和b.txt
      echo {0..4} : 输出0 1 2 3 4
    - 代码块举例:
      { a=10;b=20;};echo $a 
    - 字符串替换举例:
      A=${c:-NULL};echo $A  :如果c变量不存在,则A被赋值为NULL,否则就是c变量的值。
      A=${c:+NULL};echo $A  :  如果c变量存在,则A被赋值为NULL,否则就是c变量原来的值(不存在)。
    上例子中的NULL可以换成其它的字符串
    - 字符串匹配举例:
       temp=${file%.*} #右到左匹配,留下不匹配的
       log_date=${temp##*_} #左到右贪婪匹配,留下不匹配的
       两个%或者两个#都表示贪婪匹配。
    - 取字符
         input=0123;echo ${input:0:3}  输出: 012
     

    8、给予脚本可执行属性

    $ chmod a+x script.sh
    在执行的时候必须带上:./  指明是在当前目录
    注意shell脚本的开头行需要指定脚本执行程序: #!/bin/bash     

    9、shell脚本中的条件语句

    if [ $UID -ne 0 ]
    then echo xxx
    else echo yyy
    fi
    注意,"["后边有空格,"]"前面有空格。
    数字比较:数字小于:-lt;数字等于:-eq;数字大于:-gt
    判断一个文件是否存在
    if [ -f $FILEPATH ]
    then
      xxxx
    fi
    if [ $UU_FILE_NUM -gt 0 ] && [ ! -f ${UU_DEST} ]    # 并列条件语句
    ...
    判断目录是否存在:
    if [ ! -d "glog_log" ]
    then
        echo "create"
        mkdir glog_log
    fi
    判断某一类文件是否存在:
    思路,获取这一类文件的文件个数,判断是否大于0
    UU_ORG=*active*
    UU_FILE_NUM=`ls ${UU_ORG} |wc -l`
    if [ $UU_FILE_NUM -gt 0 ] 
    then 
    ...
    fi
    ---
    -ne —比较两个参数是否不相等
    -lt —参数1是否小于参数2
    -le —参数1是否小于等于参数2
    -gt —参数1是否大于参数2
    -ge —参数1是否大于等于参数2
    -f — 检查某文件是否存在(例如,if [ -f "filename" ])
    -d — 检查目录是否存在
     
    判断目录是否存在,不存在则创建:
    if [ ! -d "glog_log" ]
    then
        echo "Create glog_log"
        mkdir glog_log
    fi

    10、拷贝文件

    本地目录拷贝:
    cp -ri sourcedir  deskdir
    scp远程文件拷贝:
    scp intersection.exe work@xxxxhost:/home/disk2/cswuyg
    将intersection.exe从本机当前目录拷贝到远程xxxxhost机器的/home/disk2/cswuyg目录。
    目录拷贝,加上: -r
    把文件从远程拷贝到本地
    scp root@11.111.1.1:/home/work/cswuyg.test /home/work
    注意:scp需要输入远端机器密码
    拷贝文件同时也拷贝它的时间:cp -p  

    11、压缩/解压

    zip压缩:
    zip -r a.zip /home/disk9/cswuyg
    r 表示循环压缩/home/disk9/cswuyg目录下的文件。
    解压:unzip a.zip -d dest
    tar+gzip压缩:
    tar -zcvf a.tar.gz .  
    -z 使用gzip来压缩tar文件
    -v 显示文件的归档进度
    -c 创建一个新的归档
    -f 与c选项一起使用时,创建的tar文件使用该选项指定的文件名;与x一起使用时,解除该选项指定的归档。
     
    压缩某类文件:
    tar -zcvf a.tar.gz /home/cswuyg/2014-04-08*
    解压到dest目录:
    tar -xzvf a.tar.gz -C dest
    -j 使用bzip压缩:
    tar -jcvf a.temp .
     
    bz2格式文件夹解压
    bzip2 -d protobuf-2.5.0.tar.bz2
    tar -xf protobuf-2.5.0.tar 
     
    把不同目录下的文件tar到一个包里面:
    对打进tar中的文件去除根目录:tar --transform 's|.*/||g' -zcvvf my.tar.gz a b bb/c   
    transform跟着换名规则。
    资料:
    cat filelist | xargs tar -rvf archive.tar --transform='s|.*/||g'
    transform可以改变被压缩文件在tar包中的名字。

    12、删除文件/目录

    rm -r 目录名
    rm -rf 加上-f 不做删除提示
    删除带有特殊字符的文件:
    先用 ls -i 得到 1 hello world 的inod(就是最前面的数字)假设这个数字是102141122 ,然后
    find . -inum 102141122 -exec rm {} ; 就可以删除了。
    结合find删除有某些特征的文件:
    find . -name "*.log" -ctime +7 | xargs rm -f # 删除文件变更时间为7天之前且文件名以.log结尾的文件
    atime:访问时间(access time),指的是文件最后被读取的时间,可以使用touch命令更改为当前时间;
    ctime:变更时间(change time),指的是文件本身最后被变更的时间,变更动作可以使chmod、chgrp、mv等等;
    mtime:修改时间(modify time),指的是文件内容最后被修改的时间,修改动作可以使echo重定向、vi等等;

    13、并发启动多进程

    只需要在shell脚本的每行后面加上 “&” 符号。
    譬如:
    ./uu_all.exe 2014-03-20 1 > uu_old_2014-03-20.txt &
    ./uu_all.exe 2014-03-21 1 > uu_old_2014-03-21.txt &

    14、linux系统定时任务

    crontab -l  查询linux的定时任务,可以使用crontab设置定时启动某个监控进程
    crontab -e 打开该文件进行编辑
    譬如:
    00 23 * * * /home/disk11/timer_bak.sh > /home/disk11/bak_timer.log
    表明在每天23:00 执行timer_bak.sh。
    前面的5个*号位分别表示:分钟(0~59),小时(0~23),天(1~31),月份(1~12),工作日(0~6)。
    星号(*)指定该命令在每个时间阶段执行,譬如,如果小时位置是*,则表示这个命令每小时执行一次。
    如果是要指定第5、第10分钟执行该命令,那么就在分钟位置上写明:5,10,中间用都逗号分隔。
    如果要指定每3分钟执行一次,那么就是在分钟位置上写:*/3  这表示遇到能被3整除的分钟时间时执行该命令。

    15、shell下的日期

    ye=`date --date='yesterday' +%Y-%m-%d`
    echo $ye 
    这里显示格式为:2014-04-08
    或者:
    ye=`date --date='1 days ago' +%Y-%m-%d`
    打出更详细的时间
    date "+%G-%m-%d %H:%M:%S"

    16、输出重定向

    重定向是 > ,会覆盖旧数据。
    重定向累加是 >> ,不会覆盖旧数据。
     如:python a.py > a.log

    17、kill 进程

    先 ps -ef | xxx  看xxx进程情况
    找到第二列,就是进程号 ,输入 kill  进程号,如果要强杀,则在kill后面加上-9.
    批量杀进程方法1:ps -ef|grep "./xxx.sh" |grep -v grep|cut -c 9-15|xargs kill
    批量杀进程方法2:ps + awk 
    ps -ef|grep "dbpath=/home/cswuyg/shard1" | grep -v grep | awk '{print$2;}' |xargs kill 
    杀掉所有进程名为uwsgi的进程:killall uwsgi

    18、查看linux版本

        1)uname -a  : 内核版本信息
        2)cat /proc/version   :  内核版本信息
        3)cat /etc/issue    :  发行版本信息
        4)lsb_release -a  :   发行版本信息

    19、查看磁盘IO

    以MB为单位,每5秒钟刷新一次输出:iostat -xtm 5
    %util 表明磁盘使用率
    rMB/s   表示磁盘读取
    wMB/s 表示磁盘写入
     

    20、vim下dos格式文件转为unix格式文件

    在windows下编辑的shell脚本,拿到linux下无法运行,或者运行错误,很可能是由于编码问题,需要转换为unix编码,vim下的命令:
    :set fileformat=unix 或者 :set ff=unix

    21、wget拉取数据

     wget xxxhost:/home/disk8/cswuyg/uu_2014-04-14.txt
    局域网内速度可以达到110MB/s,比scp快很多。
    wget最多只能使用后缀通配符,无法使用更高级的通配符。
    指定保存文件名:
    MAC_REMOTE_MID=远程ftp路径
    MAC_LOCAL_MID=本地保存路径
    wget ${MAC_D_MID} -O ${MAC_LOCAL_MID}
     
    需要wget版本大于1.10.*版本,需要 ProFTPD 版本大于1.2.6 ,否则不能拉取大于2G的文件。
    一个wget去掉层级目录的例子:
    wget -r -nH --cut-dirs=2 ftp://xxxhost:/home/disk1/cswuyg/2014-04-04.tar.gz
    下载之后,会在本地创建cswuyg目录,并把文件下载到该目录下。
    wget拉取文件失败可能是因为远程文件权限不足,需要设置被拉取的文件的根目录:chmod 755 xxx。

    22、shell字符串匹配分割

    (1) %  从右到左匹配,如${var%.*},从右边到左边匹配var变量,发现第一个.,就把.右边被匹配了的删除,剩下.左边的
    (2) # 从左到右匹配,如$(var#*), 发现第一个,就把左边的删除,包括。
    demo:
    shell文件,a.sh
    a='1234.56&789' 
    printf ${a%.*}
    printf "
    " 
    printf ${a#*&}
    printf "
    " 
    printf $a

    输出:

    1234
    789
    1234.56&789
    %% 表示从右到左贪婪匹配
    ## 表示从左到右贪婪匹配
    demo:
    shell文件,a.sh
    a='1.2.34&56&789'
    printf ${a%%.*}
    printf "
    " 
    printf ${a##*&}                                                                                                                                     
    printf "
    " 
    printf $a 

    输出:

    1
    789
    1.2.34&56&789

    23、查看磁盘空间大小

    du -c -h --max-depth=1
    du -h --max-depth=1 本目录下,所有文件的size,--max-depth表示递归深度为1、
    du -c -h *log 查看某类文件大小

    24、shell下的通配符

    如果在shell下执行命令时,参数里面出现了*、?等通配符,这时候参数会是很多个,会把目录下的所有符合通配符的文件统统作为参数。
    这种对于python的处理非常方便,python收到的就是一个list。

    25、查看这个进程当前打开了哪些文件

    lsof -p [pid]
    or:
    ls -l /proc/[pid]/fd/

    26、修改文件的群组

    work权限的用户无法操作root权限的文件,所以需要把那些文件的群组从root修改为work。
    修改disk0举例:
    先登陆root:su root
    然后,递归修改:chown -R work disk0

    27、读取文件

    #!/bin/bash
    while read line
    do            
        echo $line
    done < xx.sh   
     
    如果不是采用while,而是采用for:
    for word in `cat bak_config`
    do
      echo $word
    done
    那么,单个单词也会被当作行输出。

    28、查看命令的可执行程序所在磁盘位置

    which ftp
    或者使用 type ftp

    29、查看进程的启动位置、可执行文件位置

    譬如查找Mongo进程的信息:
    ps -ef|grep mongo 得到进程ID,
    可执行程序位置: ll /proc/2764/exe  
    启动目录:ll /proc/2764/cwd
    打开了哪些文件:
    某个进程打开了哪些文件:ls -l /proc/[pid]/fd/

    30、find命令查找文件

     find / -name inotify.h  表示从根目录开始查找inotify.h文件。
    find . -maxdepth 1 -name "@*"   这个命令意思是,查找当前目录下以@开头的文件或者目录,搜索深度为一级也就是只在当前目录找,不进入子目录。
    查找当前目录下的b开头的文件夹下的以.tgz结尾的文件
    find . -name b* -type d -exec ls *.tgz ; 
    或者:
    find . -name b* -type d -exec find *.tgz ; 
    如果有错,也许这样子才可以(多了一个魔术字符串{}):
    find . -name 'b*' -type d -exec find {} -name '*.tgz' ; 
    搜索文本内容:
    从根目录开始查找所有扩展名为.log的文本文件,并找出包含”ERROR”的行:
    find / -type f -name "*.log" | xargs grep "ERROR"
    打印出包含这特定字符串的文件名:find .|xargs grep -ri "logxxx" -l   
    批量文件批量替换文本:
    查找个数:
    find .  -type f -name '*.*' | xargs sed -n '/2013-2014/p'
    xx换为yy:
    find . -type f -name '*.*' | xargs sed -i 's/xx/yy/g'
    find . -type f ! -path '*temp_bak*' | xargs sed -n 's/xx/yy/g'
    find . -name '*.*' | xargs  perl -pi -e 's|old|new|g'
    显示出所有包含xx的内容:find . -name '*.*' -type f | xargs sed -n '/xx/p'

    31、查看glibc的版本

    方法1:ldd --version; ldd是glibc的一部分,所以它的版本也就是glibc的版本;
    方法2:rpm -qa | grep glibc; 在centos下查看安装了哪些个glibc相关的包;
    方法3:ls -l /lib/libc.so.6; 查看libc.so.6指向哪个具体的libc so版本;
    方法4:调用C函数获取:
    #include <gnu/libc-version.h>      
    #include <iostream>                                                                                                                                                                              
    int main(void)
    {
        std::cout << gnu_get_libc_version() << std::endl;
        return 0;
    }
    注意:网络上有些人把glibc版本跟gcc版本混在一起了:glibc是Linux版的C语言运行时库,而GCC是编译工具。

    32、查看Linux Shell操作历史

    vi  ~/.bash_history

    33、文件链接

    ln [参数][源文件或目录][目标文件或目录]
     
    软链接:
    ln -s log2013.log link2013
    结果:
    link2013 -> log2013.log
    硬链接:
    ln log2013.log link2013
    会产生一个一样大小的文件,它们的链接数都会加1

    34、crontab下的输出重定向到/dev/null

    crontab里的输出,会被放到邮件缓存处,如果输出非常大可能导致tmp磁盘用尽,解决办法,把输出放弃掉,也就是重定向到/dev/null:

    0 4 * * * xxxcmd >/dev/null 2>&1

    2>&1 表示将标准错误输出也输出到标准输出中。

    标准输入:0;标准输出:1;标准错误输出:2。

    35、使用bc做计算

    echo 10 + 20 |bc
    输出:30

    36、查看ELF文件依赖的so库

    ldd XXX.exe
    查看所加载的库:
    LD_DEBUG=files ./xxx.exe
    LD_DEBUG可以修改为其它:
    bindings 显示动态链接符号绑定过程
    versions 显示符号的版本依赖关系
    查看so的导出函数:
    nm -D 7z.so
    objdump -tT 7z.so

    37、./mongod启动出现崩溃解决方法

    Floating point exception (core dumped)
    解决方法:
     LD_DEBUG=libs ./bin/mongod -v    查看所有的加载库,看在哪里崩溃了。
    最后发现是libc版本跟官网上编译出来的版本不兼容导致的。

    38、awk里的if

    ps -ef|grep mongo |awk '{if($9=="mongo"){print$9;print$2}}'  
    含义:把所有mongo进程grep出来,然后以空格、tab键分割,第9个字符串如果是mongo,则输出第9个字符串、第2个字符串。

    39、shell取字符串的前12位

    a_str=${line:0:12}
    或者,玩玩awk:
    mac_str=(`echo $line |awk '{$a=substr($0, 0, 12);print($a);}'`)

    40、利用iconv实现数据编码转换

    iconv -c -f unicode -t gb2312 cswuyg*2014-06-17_9.origin > /home/work/a.tmp
    -c 表示忽略乱码
    -f 表示源文件编码
    -t 表示目标文件编码

    41、ulimit -a

    显示当前所有资源的限制:
    如:
    open files                      (-n) 10240

    42、根据IP拿到域名/根据域名拿到IP

    host 10.242.92.26 ; 可以得到域名;
    host xxxhost ; 可以得到IP;   

    43、使用rzsz上传下载文件

    在secureCRT下,使用rz -bye 上传文件;
    sz 下载文件
    rz和sz无法使用时
    yum install lrzsz

    44、chmod 755是什么意思

    你可以在linux终端先输入ls -al,可以看到如:
       -rwx-r--r-- (一共10个参数)
    第一个跟参数跟chmod无关,先不管.
    2-4参数:属于user
    5-7参数:属于group
    8-10参数:属于others
    接下来就简单了:r==>可读 w==>可写 x==>可执行
                   r=4 w=2 x=1
    所以755代表 rwxr-xr-x

    45、使用sendmail发送邮件

    [cswuyg@xxxhost ~]$ /usr/sbin/sendmail -t << EOF
    > SUBJECT: sendmail test subject
    > TO: cswuygxx@xx.com
    > mail content
    > EOF

    46、查看进程因OOM被kill掉的命令

     dmesg |grep Kill
    ***************
    Out of memory: Kill process 24145 (python) score 637 or sacrifice child
    Killed process 24145, UID 500, (python) total-vm:21423020kB, anon-rss:20930232kB, file-rss:636kB
    ***************
    理解 OOM:
     total-vm includes both your physical RAM and swap space.

    As I understand, the size of the virtual memory that a process uses is listed as total-vm. Part of it is really mapped into the RAM itself (allocated and used). This is RSS. Part of the RSS is allocated in real memory blocks (other than mapped into a file or device). This is anonymous memory (anon-rss) and there is also RSS memory blocks that are mapped into devices and files (file-rss).

    So, if you open a huge file in vim, the file-rss would be high, on the other size, if you malloc() a lot of memory and really use it, your anon-rss would be high also. On the other side, if you allocate a lot of space (with malloc()), but nevers use it, the total-vm would be higher, but no real memory would be used (due to the memory overcommit), so, the rss values would be low.

    简单说:

    total-vm表明当前系统可以使用的内存,包括物理内存和交换区空间。

    anon-rss表明当前被声明要使用的内存。

    file-rss表明当前映射到磁盘文件的内存。

    47、中文显示乱码

    vim下的乱码,在vim下执行命令:set encoding=utf-8
    SecureCRT的乱码:在~/.bash_profile添加:export LANG=zh_CN.UTF8 ,然后重新登陆。

    48、linux命令行进入vim模式

    在命令行中输入:set -o vi

    49、查看资源占用的命令

    free -g
    top、uptime
    sar 1 1
    iostat -x 1

    50、Linux系统增加用户 (只允许root执行)

    useradd user1 创建一个新用户
    passwd user1 修改一个用户的口令

    51、查看文件系统类型,查看文件系统大小

    df -T、df -h

    52、readlink -f 获取完整路径

    如:readlink -f flume_control
    /home/cswuyg/flume/flume_control

    53、批量部署时,如何修改crontab

    远程执行修改crontab的shell命令行,譬如:
    CMD_BEFORE_COPY = "cd /home/cswuyg/;(crontab -l > crontab_bak.20140522;crontab -l;echo '20 20 * * * find /home/cswuyg/*.pb.log -mtime +3 | xargs rm -f')|crontab"

    54、mv 文件后拿着旧文件句柄的程序如何处理

    在打日志的时候,可能出现这种情况:a.log重命名为a.log1,后续的日志要求写入到新的a.log文件。
    如果有个进程拿着旧文件的句柄在写日志,通过mv对文件重命名完之后,虽然文件名改了,但是那个句柄还是有效的,还是在继续写旧文件。在日志写入时,如果要保证写入到新的a.log文件,代码中需要检查a.log文件inode信息是否发生改变,如果改变则重新打开文件。

    55、查看Linux进程树

    pstree

    56、查看二进制文件内容

    od -c a.txt

    57、查看网卡流量

    (1) watch more /proc/net/dev
    (2)watch -n 1 '/sbin/ifconfig eth0|grep bytes'  
    显示:
    Every 1.0s: /sbin/ifconfig eth0|grep bytes                                                                                                                                                Fri Jun 12 10:41:08 2014
              RX bytes:72289863517 (67.3 GiB)  TX bytes:161966405143 (150.8 GiB)
     RX 为下行流量(接收) TX 为上行流量(发送)

    58、统计端口连接数量

    netstat -nat | grep 27017 |awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -20 
    统计连接到27017端口的链接数

    59、一秒钟的时钟滴答数,跟CPU主频无关

    这个值在系统编译时设定的,如:
    [work@xxxhost boot]$ cat /boot/config.`uname -r` | grep '^CONFIG_HZ=' 
    CONFIG_HZ=1000
    C代码获取:
    printf ("_SC_CLK_TCK = %ld
    ", sysconf (_SC_CLK_TCK));
    但是,从配置文件里读到的跟用C++代码读到的不一样,可能用C++代码读到的更准确。

    60、单个进程内存使用量的限制

    配置文件:/etc/security/limits.conf

    61、make并行编译

    编译C/C++时的shell命令:make -j8 表示8个线程并发编译,要求makefile要写好依赖,否则可能会出现错误。

    62、用shell脚本设置环境变量

    shell脚本文件内容:
    --------------------------------------------------
    export PROTOC=/home/disk1/cswuyg/protobuf/install/bin/protoc
    bash
    --------------------------------------------------
    最后加上bash表明新开一个子shell环境,子shell环境继承了父shell的环境变量设置,所以PROTOC有效。
    如果没有最后的bash,那么脚本执行完之后,依然是没有PROTOC变量。

    63、查看一个进程的线程信息

    pstack [pid] | egrep -o "Thread [0-9]+ [^:]*"

    64、top命令

    只查看某个process name的多个进程:
    top -p $(pgrep -d',' -f "xxx_process_name")

    可以使用top输出到文件:

    top -b -n 1 -d 1 –c > top.log

    -b batch模式,可以重定向到文件中

    -n 一共取2次数据

    -d 每次top数据间隔为几秒

    你可以做个crontab任务一分钟调用一次追加到文件中

    -n -d 可以自己设置,单位是s

    -c 表示显示完整命令行

    top界面下的显示操作:
    P :根据CPU使用百分比排序
    M:根据驻留内存大小排序
    1:显示各个CPU信息
    c:显示完整命令行

    65、交换区是否打开

    free 命令,看Swap大小。

    66、shell脚本的输入参数

    $1是行参变量,也就是脚本执行时的第一个参数。

    CHOICE=${1:-NULL}意思是当$1为空时,自动将NULL替换成$1所要带入的变量值,这里就是$CHOICE为NULL。

    67、判断libstdc++支持哪些glibc库

     strings /usr/lib64/libstdc++.so.6 |grep GLIBC_ 

  • 相关阅读:
    封装缓动动画函数
    封装动画函数-匀速运动
    实现产品图片的放大镜效果:
    仿淘宝侧边栏滚动案例:
    页面被卷去的头部兼容性解决方案
    简单发送短信倒计时案例
    Echarts 版本的那些坑
    json变量作键名
    媒体查询那些事儿
    mac 强制关闭指定端口
  • 原文地址:https://www.cnblogs.com/xzlive/p/9487370.html
Copyright © 2020-2023  润新知