n的设计与实现
2015-11-09 10:33
239 查看
n的设计与实现
Tags:linux2015-11-06
n是TJ大神为node设计的版本管理工具,使用shell编写,是用来学习和巩固shell的很不错的例子。
源码地址:https://github.com/tj/n
源码注释:https://github.com/pastlink/n-source
设计与实现
文件存放位置
n会把下载的各个版本的node放到/usr/local/n/versions/目录中。当指定某个版本的node时,对应的node、npm命令会复制到
/usr/local/bin/目录中,lib、include等文件也会复制到
/usr/local/下对应的文件中。而全局安装的package会放到
/usr/local/lib/node_modules/目录下。
node有一个基本目录,再这个基本目录下,各个文件的布局是固定的。查看基本目录:
$ npm get prefix /usr/local
n的help
$ n -h Usage: n [options/env] [COMMAND] [args] Environments: n [COMMAND] [args] Uses default env (node) n io [COMMAND] Sets env as io n project [COMMAND] Uses custom env-variables to use non-official sources Commands: n Output versions installed n latest Install or activate the latest node release n -a x86 latest As above but force 32 bit architecture n stable Install or activate the latest stable node release n <version> Install node <version> n use <version> [args ...] Execute node <version> with [args ...] n bin <version> Output bin path for <version> n rm <version ...> Remove the given version(s) n --latest Output the latest node version available n --stable Output the latest stable node version available n ls Output the versions of node available (iojs): n io latest Install or activate the latest iojs release n io -a x86 latest As above but force 32 bit architecture n io <version> Install iojs <version> n io use <version> [args ...] Execute iojs <version> with [args ...] n io bin <version> Output bin path for <version> n io rm <version ...> Remove the given version(s) n io --latest Output the latest iojs version available n io ls Output the versions of iojs available Options: -V, --version Output current version of n -h, --help Display help information -q, --quiet Disable curl output (if available) -d, --download Download only -a, --arch Override system architecture Aliases: which bin use as list ls - rm
处理命令行参数
下面是n处理参数的代码:if test $# -eq 0; then # 参数个数为0 test -z "$(versions_paths)" && err_no_installed_print_help # versions_paths是函数 display_versions else while test $# -ne 0; do case $1 in -V|--version) display_n_version ;; # display_n_version函数里有exit -h|--help|help) display_help; exit ;; -q|--quiet) set_quiet ;; -d|--download) ACTIVATE=false ;; --latest) display_latest_version; exit ;; --stable) display_latest_stable_version; exit ;; io) set_default $1 ;; # set bin and continue project) DEFAULT=2 ;; -a|--arch) shift; set_arch $1;; # set arch and continue bin|which) display_bin_path_for_version $2; exit ;; as|use) shift; execute_with_version $@; exit ;; rm|-) shift; remove_versions $@; exit ;; latest) install_latest; exit ;; stable) install_stable; exit ;; ls|list) display_remote_versions; exit ;; *) install $1; exit ;; esac shift done fi
$#是参数数量,
$@是参数列表。
如果运行n时,没有给出任何参数,n要尝试显示当前已经安装的所有版本的node。如果没有安装任何node,则报错,并退出程序。如果有若干版本,则全屏显示,可以用上下方向键选择某一版本,回车后该版本的node生效。
假如第一个参数为
-V,
case代码块中匹配
-V后会去执行
display_n_version函数,然后break(即
;;)。出了
case代码块,通过
shift从参数列表从删除位于第一个位置的参数
-V,然后继续处理其他参数。
假如现在第一个参数是
io,则意味着要处理的不是默认的node,而是iojs,
set_default io会将这一设置放入脚本的全局变量
DEFAULT中,之后安装、删除等操作都是针对iojs的。为方便介绍,下文中都不考虑io这一情况。
假如现在第一个参数是
which,则第2个参数应该是版本号,n会调用displaybinpathforversion函数将该版本号的node的路径输出:
$ n bin 4.2.2 /usr/local/n/versions/node/4.2.2/bin/node $ n bin 4.2.3 Error: 4.2.3 is not installed
输出后程序结束。
假如现在第一个参数是
use,则下一个参数应该是版本号,此时会执行指定版本号的node或者iojs:
$ n use 4.2.2 > 1+1 2
然后退出程序。
假如现在第一个参数是
ls,
DEFAULT仍然指向默认的node,
display_remote_versions函数会被调用,该函数拉取
https://nodejs.org/dist/的网页源码,把所有的版本信息提取出来并输出,其中本地安装的版本和正在使用的版本的字体颜色会不一样。然后,程序退出。
假如现在第一个参数与给定的那些关键字都不同,则认为是一个版本号,n应该尝试去安装它。
查找指定的主、次版本号的对应的最新版本
node的安装文件是在https://nodejs.org/dist/下载的。假如现在我们要查找
4.2的最新版本,过程如下:
1、获取
https://nodejs.org/dist/网页源码:
可以用curl或者wget,这里用curl。
$ curl -s https://nodejs.org/dist/ <html> <head><title>Index of /dist/</title></head> <body bgcolor="white"> <h1>Index of /dist/</h1><hr> <pre><a href="../">../</a> <a href="latest/">latest/</a> 29-Oct-2015 21 :04 - ...........省略......... <a href="v0.10.2/">v0.10.2/</a> 03-Apr-2013 0 5:01 - <a href="v0.10.20/">v0.10.20/</a> 09-Oct-2013 17:25 - ...........省略......... </pre><hr></body> </html>
2、提取所有的链接
使用
egrep命令将所有含链接的行提取出来。
$ curl -s https://nodejs.org/dist/ | egrep '</a>' ...........省略......... <a href="v0.9.9/">v0.9.9/</a> 14-Oct-2015 10:38 - <a href="v4.0.0/">v4.0.0/</a> 08-Sep-2015 22:08 - ...........省略.........
egrep就是
grep -E。
3、把每一行的版本号提取出来
继续用
egrep把所有版本号提取出来。
$ curl -s https://nodejs.org/dist/ | egrep '</a>' | egrep -o '[0-9]+\.[0-9]+\.[0-9]+' ...........省略......... 0.8.3 0.8.4 0.8.4 0.8.5 ...........省略......... 0.9.9 4.0.0 - ...........省略.........
4、去除0.0~0.7、0.8.0~0.8.5这些版本
$ curl -s https://nodejs.org/dist/ | egrep '</a>' | egrep -o '[0-9]+\.[0-9]+\.[0-9]+' | egrep -v '^0\.[0-7]\.' | egrep -v '^0\.8\.[0-5]$'
5、去重,排序
使用
sort命令对版本号去重、排序。
$ curl -s https://nodejs.org/dist/ | egrep '</a>' | egrep -o '[0-9]+\.[0-9]+\.[0-9]+' | egrep -v '^0\.[0-7]\.' | egrep -v '^0\.8\.[0-5]$' | sort -u -k 1,1n -k 2,2n -k 3,3n -t .
6、找到以
4.2开头的所有版本
$ curl -s https://nodejs.org/dist/ | egrep '</a>' | egrep -o '[0-9]+\.[0-9]+\.[0-9]+' | egrep -v '^0\.[0-7]\.' | egrep -v '^0\.8\.[0-5]$' | sort -u -k 1,1n -k 2,2n -k 3,3n -t . | egrep "^4.2" 4.2.0 4.2.1 4.2.2
7、使用tail得到最新的版本号
$ curl -s https://nodejs.org/dist/ | egrep '</a>' | egrep -o '[0-9]+\.[0-9]+\.[0-9]+' | egrep -v '^0\.[0-7]\.' | egrep -v '^0\.8\.[0-5]$' | sort -u -k 1,1n -k 2,2n -k 3,3n -t . | egrep "^4.2" | tail -n 1 4.2.2
8、把以上命令转换成shell脚本
#!/usr/bin/env bash prefix=4.2 version=$(curl -s https://nodejs.org/dist/ 2> /dev/null \ | egrep "</a>" \ | egrep -o '[0-9]+\.[0-9]+\.[0-9]+' \ | egrep -v '^0\.[0-7]\.' \ | egrep -v '^0\.8\.[0-5]$' \ | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ | egrep ^$prefix \ | tail -n1) echo $version
安装某一版本
安装某一版本时,调用的是install函数,参数是版本号。主要流程如下:
如果版本号只给出了主、次版本,没有给修订版本,则拉取最新的修订版本号。
若该版本对应的目录存在,且目录下没有
n.lock文件(有则意味着正在被其他运行的n安装),意味着该版本已经被安装,根据其他条件判断是否激活该版本,然后退出。
生成该版本对应的安装文件的url,判断该url是否有效(返回200),无效则退出。
创建该版本对应的目录,并在该目录下创建文件
n.lock,代表正在安装。下载文件,解压到该目录。
删除
n.lock,安装完成。
根据其他条件判断是否激活该版本,然后退出。
这里非常有意思的是用
n.lock代表安装状态。
如何进入全屏、退出全屏
下面的例子可以用来理解如何进入全屏、退出全屏:#!/usr/bin/env bash enter_fullscreen() { tput smcup # Save the display stty -echo # 不回显输入的字符 } leave_fullscreen() { tput rmcup # Restore the display stty echo # 回显输入的字符 } enter_fullscreen echo "已经进入全屏" sleep 12 leave_fullscreen
捕捉方向键
方向键对应长度为3的特殊字符,可以在InputTranslation找到这些按键的字符标识。
下面是一个示例:
#!/usr/bin/env bash while true; do read -n 3 c # 读取3个字符放入变量c中 case "$c" in $'\033[A') echo "上方向键" ;; # 相当于break $'\033[B') # 下方向键 echo "下方向键" ;; $'\033[D') # 下方向键 echo "左方向键" ;; $'\033[C') # 下方向键 echo "右方向键" ;; *) # 默认 echo $c # 如果直接回车,$c是空字符串 echo "退出程序" exit ;; esac done
如何退出上面的程序呢?
方法1是按回车键。 方法2是依次按三个数字或者字母或者其他字符,只要达到三个,就会退出。
一个小问题,回车键如何捕捉,见下面的代码:
#!/usr/bin/env bash while true; do read -n 3 c case "$c" in "") printf "\t enter \n" ;; *) exit ;; esac done
如何激活某个版本的node
这里的“激活”就是指将某一版本的node、npm等文件从/usr/local/n/versions/拷贝到
/usr/local/bin,其他的相关文件也拷贝到对应目录的动作。
在n中,该功能由
display_versions函数实现。
在终端输入n,回车后会进入全屏:
此时,通过执行
check_current_version函数得到当前使用的node版本,通过
versions_paths函数得到本机安装的所有node版本,并排序。
display_versions_with_selected函数用来显示本机所有的node版本,并高亮目前在使用的版本。
然后在一个while循环里监视键盘的输入,如果是上方向键或者下方向键选择其他的版本,就清屏,用
display_versions_with_selected函数用来显示本机所有的node版本,并高亮目前选择的版本。
如果输入的是其他字符,则激活当前选中的版本,退出程序。
删除某个版本的node
删除操作由remove_versions函数实现。思路很简单,如果要删除的版本和当前在使用的版本不一致,则直接在
/usr/local/n/versions/目录中删除对应版本的整个目录;若一致,则不删除。
remove_versions函数可以接受多个版本号作为参数。
隐藏/显示光标、删除当前行
先看下面的示例:(如何制作gif图片,可以参考Linux下GIF制作指南)
代码为:
#!/usr/bin/env bash hide_cursor() { printf "\e[?25l" } show_cursor() { printf "\e[?25h" } erase_line() { printf "\033[1A\033[2K" } hide_cursor echo "hide_cursor" sleep 4 erase_line show_cursor echo "show_cursor" sleep 4 erase_line
这里面就是特殊控制字符的使用。在
erase_line函数中,
033是八进制,十进制值是27,在ASCII表中代表特殊字符ESC
(escape),转义的意思。
\033[1A是将光标移动到前一行,
\033[2K是清除光标所在行。
资料:
Terminal
codes (ANSI/VT100) introduction
ANSI
questions: “... x1B ..?25h” and ... x1BE”
ANSI
escape code
Using
read without triggering a newline action on terminal
n的Makefile
下面是n的Makefile:PREFIX ?= /usr/local install: bin/n mkdir -p $(PREFIX)/$(dir $<) cp $< $(PREFIX)/$< uninstall: rm -f $(PREFIX)/bin/n .PHONY: install uninstall
变量赋值
?=是赋值操作符,如果PREFIX已经有值就仍为原值,否则就用
/usr/local。
关于赋值,可以参考Makefile
中:= ?= += =的区别
dir命令
dir用于列出目录中内容,例如:$ dir /usr/ bin games include lib local NX sbin share src $ dir /etc/passwd /etc/passwd
不过在Makefile里,
$(dir path/to/file)是用来获取目录的。这个可以参考8.3
Functions for File Names。
例如下面的Makefile:
test: echo $(dir /etc/hosts) $(dir /etc/hosts)
执行结果如下:
$ make test echo /etc/ /etc/ /etc/ make: execvp: /etc/: Permission denied make: *** [test] Error 127
上面报了一个
Permission denied的错误,这是因为make尝试将
/etc/当作可执行命令去执行了。
文件依赖
举个例子,有的makefile可能有类似下面的内容:prog1: prog1.o utils.o cc -o prog1 prog1.o utils.o
这是在告诉make,目标文件prog1的生成依赖于prog1.o、utils.o。若依赖文件有缺失,会报错。
$<、$@、$^
$@:目标文件
$^:所有的依赖文件
$<:第一个依赖文件
下面举个例子:
新建一个Makefile文件,内容如下(注意要用tab进行缩进):
prog1: prog1.o utils.o echo $@ echo $^ echo $<
执行make:
$ make prog1 make: *** No rule to make target `prog1.o', needed by `prog1'. Stop.
为了快速解决这个报错,我们伪造两个
.o格式的文件:
$ touch prog1.o $ touch utils.o
现在运行make:
$ make prog1 echo prog1 prog1 echo prog1.o utils.o prog1.o utils.o echo prog1.o prog1.o
.PHONY
PHONY的含义是:假的、伪造的。用来说明哪些文件是假的,例如n的Makefile中目标文件install、uninstall就是假的。
默认操作
定义目标文件all即可。例如Makefile内容如下:
prog1: prog1.o utils.o echo $@ echo $^ echo $<
all: prog1
运行结果:
$ make echo prog1 prog1 echo prog1.o utils.o prog1.o utils.o echo prog1.o prog1.o
参考资料
玩转Bash脚本:特殊变量shell编程——if语句
if -z -n -f -eq -ne -lt
linux中shell变量$#,$@,$0,$1,$2的含义解释
Terminal
control/Preserve screen
ANSI
Escape Sequences: Colours and Cursor Movement
Bash
Prompt HOWTO
shell中${
} 的一些特异功能
细碎的知识点
以下是我阅读n源码时候整理的细碎的知识点,与n的设计无关。
$#
作用:获取参数个数。示例:
#!/usr/bin/env bash echo $#
用例:
$ bash mytest.sh 0 $ bash mytest.sh foo 1 $ bash mytest.sh foo bar 2
${var-value}
value作为默认值。如果$var是空值,那么使用value。示例:
#!/usr/bin/env bash N_PREFIX=${N_PREFIX-/usr/local} echo $N_PREFIX
用例:
$ bash mytest.sh /usr/local $ N_PREFIX=/usr bash mytest.sh /usr
$* 与 $@
通配符*将所有参数视作一个变量,而@则可以理解为所有参数的集合。
数组
linuxshell 数组建立及使用技巧
Linux
Shell数组和关联数组
示例:
#!/usr/bin/env bash BINS=("node" "io") echo $BINS # 输出node echo ${BINS[*]} # 输出node io echo ${BINS[0]} # 输出node echo ${BINS[1]} # 输出io echo ${#BINS[*]} # 输出2, 数组长度 # 遍历,依次输出node,io for var in ${BINS[*]} do echo $var done
运行结果:
$ bash mytest.sh node node io node io 2 node io
判断语句中的-n,-z
if [ -n $string ]:如果string
非空(非0),返回0(true)。
if [ -z $string ]:如果string
为空。
示例:
#!/usr/bin/env bash BINS=("node" "io") echo "PROJECT_NAME: $PROJECT_NAME" echo "PROJECT_URL: $PROJECT_URL" if [ -n "$PROJECT_NAME" ]; then # 如果不为空 BINS+=($PROJECT_NAME) # 数组中追加元素 if [ -z "$PROJECT_URL" ]; then # 如果为空 echo "Must specify PROJECT_URL when supplying PROJECT_NAME" fi fi echo ${BINS[*]} # 输出数组中所有元素
输出:
$ bash mytest.sh PROJECT_NAME: PROJECT_URL: node io $ PROJECT_NAME="dev" bash mytest.sh PROJECT_NAME: dev PROJECT_URL: Must specify PROJECT_URL when supplying PROJECT_NAME node io dev $ PROJECT_NAME="dev" PROJECT_URL="urlllll" bash mytest.sh PROJECT_NAME: dev PROJECT_URL: urlllll node io dev
curl命令的若干参数
-#: 用于显示进度条。
-L: 用于跳转。如果访问的网页响应3××,则去请求新的网址。
-s:--silent,即quiet。
wget命令的参数
--no-check-certificate:
不校验证书。
-q: quiet,关掉wget的输出。
-O:
指定获取的数据存放的位置。
下面的命令是将数据存放在baidu.html这个文件中:
$ wget http://www.baidu.com -O baidu.html --2015-11-05 10:44:45-- http://www.baidu.com/ Resolving www.baidu.com (www.baidu.com)... 119.75.218.70, 119.75.217.109 Connecting to www.baidu.com (www.baidu.com)|119.75.218.70|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 761 Saving to: ‘baidu.html’ ....
下面的命令是将数据输出到终端:
$ wget http://www.baidu.com -O- --2015-11-05 10:45:58-- http://www.baidu.com/ Resolving www.baidu.com (www.baidu.com)... 119.75.218.70, 119.75.217.109 Connecting to www.baidu.com (www.baidu.com)|119.75.218.70|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 761 Saving to: ‘STDOUT’ ....
去掉多余的信息,将数据输出到终端:
$ wget http://www.baidu.com -O- -q <!DOCTYPE html><html><body><script type="text/javascript">var u='https://www.baidu.com/?tn=91055223_hao_pg&rsr=5',ua=navigator.userAgent.toLowerCase();if(u.indexOf('baidu.com')>0||u.indexOf('360.cn')>0||u.indexOf('hao123.com')>0){var cc = document.cookie.split(';');for(var i=0;i<cc.length;i++){var name = cc[i].split("=")[0];document.cookie = name + '=; path=/; domain=.baidu.com; expires=Thu, 01 Jan 1970 00:00:01 GMT;';}}if(ua.indexOf('applewebkit')>0){var h = document.createElement('a');h.rel = 'noreferrer';h.href = u;document.body.appendChild(h);var evt = document.createEvent("MouseEvents");evt.initEvent("click", true, true);h.dispatchEvent(evt);} else {document.write('<meta http-equiv="Refresh" Content="0; Url=' + u + '" >');}</script></body></html>
command命令
$ command -v wget /usr/bin/wget $ command -v wget >/dev/null $ command -v wget && echo "has wget" /usr/bin/wget has wget $ command -v wget >/dev/null && echo "has wget" has wget
脚本的参数
示例:#!/usr/bin/env bash echo "脚本名:$0" echo "参数个数:$#" echo "所有参数:$@" echo "第1个参数:$1" echo "第2个参数:$2"
用例:
$ bash mytest.sh 脚本名:mytest.sh 参数个数:0 所有参数: 第1个参数: 第2个参数: $ bash mytest.sh --name=letian -q 脚本名:mytest.sh 参数个数:2 所有参数:--name=letian -q 第1个参数:--name=letian 第2个参数:-q
函数的参数
示例:#!/usr/bin/env bash function foo() { echo "脚本名:$0" echo "参数个数:$#" echo "所有参数:$@" echo "第1个参数:$1" echo "第2个参数:$2" } foo echo # 添加空行 foo --name=letian -q
关键字
function可以省略。
运行结果:
脚本名:mytest.sh 参数个数:0 所有参数: 第1个参数: 第2个参数: 脚本名:mytest.sh 参数个数:2 所有参数:--name=letian -q 第1个参数:--name=letian 第2个参数:-q
前一命令的退出码$?
编写mytest.sh:#!/usr/bin/env bash exit 1
测试:
$ bash mytest.sh $ echo $? 1
0代表正常退出。
$$
$$是当前进程的pid。
示例:
$ echo $$ 7662
tput命令
tput命令行使用说明
Terminal
control/Preserve screen
关于smcup、rmcup,可以在终端中依次输入下面的命令看看效果:
tput smcup # Save the display echo 'Hello' tput rmcup # Restore the display
将命令执行的结果放入一个变量中
有两种方法,一个是$(),另外一种是是用反引号```。
示例:
$ result=$(ls) $ echo $result baidu.html mytest.sh $ result="$(ls)" $ echo $result baidu.html mytest.sh $ result=`ls` $ echo $result baidu.html mytest.sh
node命令直接执行字符串中的nodejs代码
$ node -p "1+1;" 2 $ node -p "console.log(1+1);" 2 undefined
grep命令的-A、-B参数
关于函数中变量的取值范围
要函数中定义的变量只在函数中有效,需要使用local关键字。 示例:#!/usr/bin/env bash foo() { bar="hi" local var="hello" } foo echo "$bar" # 输出hi echo "$var" # 输出空字符
键盘中特殊键与字符的对应
上方向键与\033[A对应,下方向键与
\033[B对应。更多见Input
Translation。
这些字符的长度为3:
$ char=$'\033[A'; echo ${#char} 3
for 循环
示例1:#!/usr/bin/env bash for subdir in bin lib include share; do echo $subdir done
输出:
bin lib include share
关于Pax
PaX- Wikipedia
MPROTECT
字符串中字符的替换
示例:#!/usr/bin/env bash version=4.2.2 echo ${version//./ } # 将.替换微空格 version=v4.2.2 echo ${version//./--} # 将.替换为--
运行结果:
4 2 2 v4--2--2
提取字符串中数字
示例:#!/usr/bin/env bash semver="004 2 2" echo $semver | grep -o -E '[0-9]+' # 分行输出004、2、1 echo $semver | grep -o -E '[0-9]+' | head -1 # 输出004 echo $semver | grep -o -E '[0-9]+' | head -1 | sed -e 's/^0\+//' # 输出4 echo $semver | awk '{print $2}' # 输出2
grep的
-o是指只输出匹配的部分,
-E指扩展的正则表达式。
head -1是把第一行提取出来。
sed -e 's/^0\+//'是把最前面的0替换为空。
使用shift删除指定数量的参数
shift命令用于删除参数列表中的前若干个参数,默认是1,也可以指定数量。示例:
#!/usr/bin/env bash foo() { echo $@ shift echo $@ shift 3 echo $@ } foo 1 2 3 4 5 6
运行结果:
1 2 3 4 5 6 2 3 4 5 6 5 6
字体颜色配置
我们在设置PS1变量的时候常常与颜色打交道。使用printf、echo命令时也可以设置字体颜色,例如:033是八进制,十进制值是27,在ASCII表中代表特殊字符ESC
(escape),转义的意思。36m对应的颜色是Cyan,,91m对应的颜色是red,0m的作用是重置。
资料:
Chapter
6. ANSI Escape Sequences: Colours and Cursor Movement
Color
Bash Prompt - ArchLinux
[What does a bash sequence '\033999D'
mean and where is it explained?
Ultimate
GIT PS1 bash prompt
sort命令
-k参数的解释:
-k, --key=POS1[,POS2] start a key at POS1 (origin 1), end it at POS2(default end of line)
position是从1开始的。
示例1:
#!/usr/bin/env bash cat <<EOF | sort -k 1 -t , 4,23,12 3,26,1 4,4,16 5,4,4 5,0,4 EOF
运行结果:
3,26,1 4,23,12 4,4,16 5,0,4 5,4,4
示例2:
#!/usr/bin/env bash cat <<EOF | sort -k 1,1 -t , 4,23,12 3,26,1 4,4,16 5,4,4 5,0,4 EOF
运行结果:
3,26,1 4,23,12 4,4,16 5,0,4 5,4,4
从第2、3行可以看到,23<4,这是按照字符串来比较的。
示例3:
#!/usr/bin/env bash cat <<EOF | sort -k 1,2n -t , 4,23,12 3,26,1 4,4,16 5,4,4 5,0,4 EOF
1,2n是指将第1个和第2个字段放在一起,当作数字来排序,n就numeric
sort。 所以运行结果是:
4,4,16 5,0,4 5,4,4 3,26,1 4,23,12
示例4:
#!/usr/bin/env bash cat <<EOF | sort -k 1,1n -k 2,2n -t , 4,23,12 3,26,1 4,4,16 5,4,4 5,0,4 EOF
运行结果:
3,26,1 4,4,16 4,23,12 5,0,4 5,4,4
相关文章推荐
- QA Sign off template
- uml之Robustness Diagram
- poj 1328 贪心算法和快排(快排细节)
- MVC 和 MVVM
- 打开手机手电筒
- 《从零开始学Swift》学习笔记(Day 33)——属性观察者
- 阿里云服务器密码说明
- 异步任务执行之-队列
- iOS -程序启动原理和UIApplication的介绍
- 随笔
- nginx no-cache
- oracle 简单序列 自增 实例
- 各种加密算法的速度对比
- iOS -程序启动原理和UIApplication的介绍
- 手机端apk文件安装
- 11月初.wang域名总量TOP15:13家中国域名商上榜
- js页面效果
- 利用maven中resources插件的copy-resources目标进行资源copy和过滤
- Android 监听wifi总结
- DBMS_STATS.GATHER_TABLE_STATS详解