无忧启动论坛

 找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
楼主: 不点
打印 上一主题 下一主题

cish 开发构想

    [复制链接]
31#
 楼主| 发表于 2018-3-11 10:51:52 | 只看该作者
本帖最后由 不点 于 2018-3-11 23:09 编辑
不知 发表于 2018-3-11 10:20
确实需要flush。不过直接编写程序是不需要的。

受到你的启发,对于 cout,我也找到了一个办法。

如果先执行一条

cout << unitbuf;

那么,后续的 cout 就会即时打印。

如果执行一条

cout << nounitbuf;

那么后续的 cout 就会按行缓存,遇到回车才开始输出一行。

对于 printf,我还没找到对策。【更新】找到了,非常棒:

https://stackoverflow.com/questions/1716296/why-does-printf-not-flush-after-the-call-unless-a-newline-is-in-the-format-strin


The stdout stream is buffered, so will only display what's in the buffer after it reaches a newline (or when it's told to). You have a few options to print immediately:

Print to stderr instead using fprintf:

fprintf(stderr, "I will be printed immediately");

Flush stdout whenever you need it to using fflush:

printf("Buffered, will be flushed");
fflush(stdout); // Will now print everything in the stdout buffer

Edit: From Andy Ross's comment below, you can also disable buffering on stdout by using setbuf:

setbuf(stdout, NULL);

就是说,先执行一条 setbuf(stdout, NULL); 就 OK 了。

【补充】但是当使用了 setbuf(stdout, NULL); 之后,我不知道如何恢复为以前的状态(即,缓冲输出的状态)。所以,我感觉还是

printf(...); fflush(stdout);

的方法比较好。这可以写成一个函数(也可以写成一个宏),让它自动 flush。只要不使用 fflush 函数,就仍然是缓冲输出的状态了。

点评

虽然没法直接恢复,但可以用setvbuf设置缓冲(模式:行缓冲,无缓冲,满缓冲)。 —————————————————————————————————————————— [attachimg]368193[/attachimg]  详情 回复 发表于 2018-3-11 14:52

评分

参与人数 1无忧币 +5 收起 理由
不知 + 5 很给力!

查看全部评分

回复

使用道具 举报

32#
发表于 2018-3-11 14:52:28 | 只看该作者
不点 发表于 2018-3-11 10:51
受到你的启发,对于 cout,我也找到了一个办法。

如果先执行一条

虽然没法直接恢复,但可以用setvbuf设置缓冲(模式:行缓冲,无缓冲,满缓冲)。
——————————————————————————————————————————

点评

不错,又深入了一步。要是能够 get 出 stdout 原有的 buffer,那该多好啊?  详情 回复 发表于 2018-3-11 16:54
回复

使用道具 举报

33#
 楼主| 发表于 2018-3-11 16:54:15 | 只看该作者
不知 发表于 2018-3-11 14:52
虽然没法直接恢复,但可以用setvbuf设置缓冲(模式:行缓冲,无缓冲,满缓冲)。
—————————— ...

不错,又深入了一步。要是能够 get  出 stdout 原有的 buffer,那该多好啊?
回复

使用道具 举报

34#
发表于 2018-3-11 17:52:51 | 只看该作者
嗯,用公众号登进去又测试了下,这样试了更多的命令,看起来还不错。各反馈如下:
看不合法的提示,应当氏 管道符 和 重定向符不支持的啦。不过确实氏个能用的shell了。

[cling]$ mv ttt1.uxt ttt3.uxt
[cling]$ cat ttt* > ttt03.uxt
this ttt3.uxt file
wordexp: Illegal occurrence of newline or one of |, &, ;, <, >, (, ), {, }.
err=2, cmd=cat ttt* > ttt03.uxt
input_line_12:2:2: error: unknown type name 'cat'
cat ttt* > ttt03.uxt
^
input_line_12:2:9: error: expected ';' at end of declaration
cat ttt* > ttt03.uxt

[cling]$ cat ttt ttt3.uxt > ttt03.uxt
wordexp: Illegal occurrence of newline or one of |, &, ;, <, >, (, ), {, }.
err=2, cmd=cat ttt ttt3.uxt > ttt03.uxt
input_line_13:2:2: error: unknown type name 'cat'
cat ttt ttt3.uxt > ttt03.uxt
^
input_line_13:2:9: error: expected ';' at end of declaration
cat ttt ttt3.uxt > ttt03.uxt
        ^
        ;
[cling]$ vi ttt
[cling]$ vi ttt
[cling]$ vi ttt03.uxt
[cling]$ pwd
/home/public
[cling]$ free
              total        used        free      shared  buff/cache   available
Mem:        1009308      134908       67924       10232      806476      676368
Swap:       1048572      168704      879868
[cling]$ date
Sun Mar 11 09:37:10 UTC 2018
[cling]$ grep "test" ttt
this a test line.

for test cish.
[cling]$ tail ttt03.uxt
this ttt3.uxt file
for test cish de shell cmd.

[cling]$
[cling]$ q
Command not found: q
input_line_14:2:2: error: use of undeclared identifier 'q'
q
^
[cling]$ quit
Command not found: quit
input_line_15:2:2: error: use of undeclared identifier 'quit'
quit
[cling]$ exit
public@ttyd:~$
logout

点评

没错,以下这些内容还没支持: 1、命令以及参数的自动补全。 2、管道 3、输入输出重定向 4、后台执行命令,以及作业控制(job control)等  详情 回复 发表于 2018-3-11 18:08
回复

使用道具 举报

35#
 楼主| 发表于 2018-3-11 18:08:12 | 只看该作者
本帖最后由 不点 于 2018-3-12 08:14 编辑
gnuxwy 发表于 2018-3-11 17:52
嗯,用公众号登进去又测试了下,这样试了更多的命令,看起来还不错。各反馈如下:
看不合法的提示,应当氏 ...


没错,以下这些内容还没支持:

1、命令以及参数的自动补全。
2、管道
3、输入输出重定向
4、信号处理
5、后台执行命令,以及作业控制(job control)等

回复

使用道具 举报

36#
发表于 2018-3-11 22:53:04 来自手机 | 只看该作者
看不懂,纯掺和。

点评

欢迎光临,欢迎指导。  发表于 2018-3-11 23:12
回复

使用道具 举报

37#
发表于 2018-3-12 20:30:49 | 只看该作者
不用急,大师慢慢完善cish就行。。。以后更成熟了,就可以成为cling一个有趣的分支版。

点评

是的,急不来的。时间越久,就越能锤炼出好东西。每个人在不同的时期,会有不同的思路。随着时间的推移,每个人都在进步,外界环境也在变化,说不定当初以为很难做的事情,到那时,水到渠成,不难了。  详情 回复 发表于 2018-3-13 04:15
回复

使用道具 举报

38#
 楼主| 发表于 2018-3-13 04:15:48 | 只看该作者
本帖最后由 不点 于 2018-3-13 16:07 编辑
gnuxwy 发表于 2018-3-12 20:30
不用急,大师慢慢完善cish就行。。。以后更成熟了,就可以成为cling一个有趣的分支版。


是的,急不来的。时间越久,就越能锤炼出好东西。每个人在不同的时期,会有不同的思路。随着时间的推移,每个人都在进步,外界环境也在变化,说不定当初以为很难做的事情,到那时,水到渠成,不难了。

一方面要能沉得住气,等到技术成熟再下手,不要匆忙。另一方面,对于感兴趣的各位大人来说,一旦在某方面已经考虑成熟,拖延不是一个选项,该出手时就出手。这软件不是我的,而是大家的。大家共同开发,进步才会快。该出手时不出手,让时光白白流逝,将来会后悔的。

回复

使用道具 举报

39#
 楼主| 发表于 2018-3-13 05:59:59 | 只看该作者
记录一下,Windows 下的 rcp 是无用的(把我折腾得够呛),根本与 Linux 不兼容。最后终于找到了 pscp 这个工具,可以在 Windows 和 Linux 之间传输文件,其功能相当于 linux 的 rcp 命令,用法也与 linux 的 rcp 相同(或类似)。

https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html

上面是 putty 的官方下载页,只需下载 pscp 即可,无需下载 putty。

点评

pscp是命令行,如果想复制的文件多的话,可以用带界面的WinSCP  发表于 2018-3-13 09:33
回复

使用道具 举报

40#
 楼主| 发表于 2018-3-13 11:15:01 | 只看该作者
记录一下(方便以后找到这个资料),目前在学习《Shell Command Language》
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html

评分

参与人数 1无忧币 +5 收起 理由
wuyou + 5 不错,我也收藏一下这个链接

查看全部评分

回复

使用道具 举报

41#
 楼主| 发表于 2018-3-13 13:23:14 | 只看该作者
今天又改动了一点点。以数字( 0~9 )或左括号( “(” ) 开头的行,都作为 C 代码来处理。这样方便用 C 语言的功能来在命令行下进行计算。shell 本身也能计算,但是需要像这样

expr  3 + 5
expr  2 \* 7
echo  $(( 5 * 9 ))

比较累赘。而用 cish 的命令行,直接敲入 5*7 回车,得到 (int) 35,这就快捷多了。
回复

使用道具 举报

42#
 楼主| 发表于 2018-3-13 17:42:20 | 只看该作者
在 shell 规范中,shell 也有函数。我在考虑,最好是能把 shell 的函数与 C 的函数进行某种整合,统一处理。
回复

使用道具 举报

43#
发表于 2018-3-14 22:44:41 | 只看该作者
嗯,老大应该在本贴的首楼中,直接贴上网址,公用帐号,密码,方便有兴趣的坛友点进来就能进去瞧瞧。

屮目前编程水平未入门,最近几年如果有时间,也会专注于弄个自已能用的输入法,毕竟一直没有自已用
得爽的输服台,心里总氏不舒服,不管时间多长,反正有生之年一定要搞定它。等搞定这个问题之后,如果
水平提高了,或许会参与其他的开源项目。

目前嘛,只能氏闲逛其他gnux网站,论坛,贴吧时顺便帮老大宣传一下啦。。。

回复

使用道具 举报

44#
 楼主| 发表于 2018-3-15 08:41:34 | 只看该作者
今天了解了 cling 的输出重定向。为了让 cling 不显示出错信息,找了很久,都没找到办法。用重定向的方法,算是权宜之计。

输入
  1. .2> /dev/null
复制代码


后续的出错信息都看不见了。

再输入
  1. .2>
复制代码


(文件名的位置是空的,即,不填文件名,其作用是撤销前面的重定向),则后续的出错信息就又能显示出来了。
回复

使用道具 举报

45#
 楼主| 发表于 2018-3-16 10:28:33 | 只看该作者
本帖最后由 不点 于 2018-3-20 15:26 编辑

正如以前所说的,整合就需要权衡。经过一段时间的实践和认识,现在我又回到 “以 C 为重心” 的思路上了。

昨天找到了屏蔽 Cling 出错信息的办法。这不彻底。彻底的办法应该是把出错信息保存起来,当需要的时候,让它显现;当不需要的时候,让它隐藏。但出错信息不可以保存在磁盘文件上(影响执行效率,也影响磁盘寿命),应该保存在内存中。

如果找到这样的办法,就可以首先用 C 解释,当出现语法错误时,再按 shell 命令来解释。

当涉及到 “编程” 这个话题的时候,还得依靠 C,不能依靠 shell。

shell 主要只是用来运行命令罢了。




为什么要先用 C 解释呢?因为处理逻辑简单。C 解释时,出现语法错误的,都可以当作 Shell 来解释,不啰嗦。如果先用 shell 解释,为了不把 C 代码当成 shell 来解释,就需要用排除法,排除很多具有 C 特征的行,而且尽管排除了很多,也难以全面彻底地排除。




当敲入 ls 之类的 shell 命令时,由于 Cling 把它当成 C 语言代码来处理,因此 Cling 会报错。要想屏蔽出错信息,可以注释掉

src/tools/clang/lib/Sema/SemaExpr.cpp

中如下一行(这是通过艰苦调试发现的!)

  Diag(R.getNameLoc(), diagnostic) << Name;

但若想把出错信息保存在某个字符串中,则相当不容易,因为 C++ 比 C 复杂得多,光是找 Diag () 的定义,我都搞不定。【后来通过把 cerr 重定向到 stringstream 中巧妙解决了这个问题。】

点评

有个tinycc,很小的C语言编译解释器,你把解析的部分拿出来, 先用解析器跑下输入的代码,能过就当C,不能就当shell。 你通过个别字符的方式,简单语句还行,复杂些会出问题。 玩耍到研究方向的话, 引入神经  详情 回复 发表于 2018-3-16 19:30
回复

使用道具 举报

46#
发表于 2018-3-16 19:30:53 | 只看该作者
不点 发表于 2018-3-16 10:28
正如以前所说的,整合就需要权衡。经过一段时间的实践和认识,现在我又回到 “以 C 为重心” 的思路上了。
...

有个tinycc,很小的C语言编译解释器,你把解析的部分拿出来,
先用解析器跑下输入的代码,能过就当C,不能就当shell。
你通过个别字符的方式,简单语句还行,复杂些会出问题。

玩耍到研究方向的话,
引入神经网络,给他shell和C的代码训练识别度,
很快就可以到一个满意的识别度,不过编程语言这种特别规范的,不太需要,
还是标准解析过一遍实在。

点评

不错的思路。我其实挺喜欢小的东西。假如 cling 啃不动的话,可能我就会采用 tinycc 之类的小工具了。 希望有人去做 tinycc 的工作。  详情 回复 发表于 2018-3-16 23:23
回复

使用道具 举报

47#
 楼主| 发表于 2018-3-16 23:23:33 | 只看该作者
slore 发表于 2018-3-16 19:30
有个tinycc,很小的C语言编译解释器,你把解析的部分拿出来,
先用解析器跑下输入的代码,能过就当C,不 ...

不错的思路。我其实挺喜欢小的东西。假如 cling 啃不动的话,可能我就会采用 tinycc 之类的小工具了。

希望有人去做 tinycc 的工作。
回复

使用道具 举报

48#
 楼主| 发表于 2018-3-18 04:57:13 | 只看该作者
本帖最后由 不点 于 2018-3-20 15:59 编辑

现在已经调整为优先用 C 解释。当用 C 解释失败时,再用 shell 命令来解释。

在命令行敲入 M_PIM_PIl
(右边是小写的 L 表示双精度,不是数字 1回车,可打印出圆周率 π 的值。
在命令行敲入 M_EM_El (右边是小写的 L 表示双精度,不是数字 1)回车,可打印出自然对数的底 e 的值。

以上常数是在 math.h 中定义的,可以用来进行数值计算。优先用 C 解释的好处是,宏定义以及全局常量、全局变量、全局函数,都能直接使用。

敲入 chdir obj 回车,会进入 obj 子目录中。以下是处理过程:


  1. [cling]% chdir obj
  2. input_line_15:2:7: error: expected ';' after expression
  3. chdir obj                  由于先用 C 解释,所以会报错。
  4.       ^
  5.       ;
  6. input_line_15:2:8: error: use of undeclared identifier 'obj'
  7. chdir obj
  8.        ^
  9. input_line_16:2:8: error: use of undeclared identifier 'obj'
  10. chdir(obj)  失败后,进行第 2 次尝试,这次加上括号。但仍然失败。
  11.        ^
  12. (int) 0  最后为什么成功了呢?因为进行了第三次尝试:为参数加上了引号 chdir("obj") 当然就成功了。注意 chdir 是 C 的库函数(或者是系统调用)。下面的 pwd 命令能够验证确实进入 obj 子目录了。
  13. [cling]% pwd
  14. input_line_19:2:2: error: use of undeclared identifier 'pwd'
  15. pwd                同样地,先用 C 解释 pwd 是失败的。
  16. ^
  17. input_line_20:2:2: error: use of undeclared identifier 'pwd'
  18. pwd()              自动加上括号,当作函数调用,再试一次。但仍然失败。
  19. ^
  20. input_line_21:2:2: error: use of undeclared identifier 'pwd'
  21. pwd(0)         第三次尝试,加上参数 0。仍然失败。
  22. ^
  23. input_line_22:2:2: error: use of undeclared identifier 'pwd'
  24. pwd("")        第四次尝试,参数换成空字符串。仍然失败。
  25. ^
  26. /home/user/obj  最后为什么成功了呢?因为是交给 shell 模块执行了。这条信息是外部命令 pwd 打印出来的。
  27. [cling]%
复制代码
回复

使用道具 举报

49#
 楼主| 发表于 2018-3-18 05:10:25 | 只看该作者
再举一例,用 cd obj 来进入 obj 目录:

  1. [cling]$ cd obj
  2. input_line_11:2:2: error: unknown type name 'cd'
  3. cd obj              先用 C 来解释,当然是失败的。
  4. ^
  5. input_line_12:2:5: error: use of undeclared identifier 'obj'
  6. cd(obj)       自动加上括号,进行第二次尝试,结果仍然失败。
  7.     ^
  8. input_line_13:2:2: error: use of undeclared identifier 'cd'
  9. cd("obj")     自动加上引号,进行第三次尝试,结果仍然失败(因为不存在 cd 这个函数)。
  10. ^
  11. 然而,下面的 pwd 命令却证实,cd obj 执行成功了。为什么呢?因为自动进行了第四次尝试,即 交给 shell 处理模块来执行。由于 shell 模块当中有个内部命令叫做 cd,所以就执行成功了。
  12. [cling]% pwd
  13. input_line_14:2:2: error: use of undeclared identifier 'pwd'
  14. pwd
  15. ^
  16. input_line_15:2:2: error: use of undeclared identifier 'pwd'
  17. pwd()
  18. ^
  19. input_line_16:2:2: error: use of undeclared identifier 'pwd'
  20. pwd(0)
  21. ^
  22. input_line_17:2:2: error: use of undeclared identifier 'pwd'
  23. pwd("")
  24. ^
  25. /home/user/obj
  26. [cling]%
复制代码
回复

使用道具 举报

50#
 楼主| 发表于 2018-3-18 05:28:14 | 只看该作者
再举一例,用 exit 退出 cish 环境:

  1. [cling]% exit
  2. (void (*)(int) __attribute__((noreturn)) throw()) Function @0x7f7d38e25f00
  3. 看到没有?先用 C 解释,就成功了!因为 exit 确实是个系统调用,是个已经定义了的函数,它的地址被打印出来了。

  4. 由于已经发现它是函数,因此,进行第二次计算,这次加上括号:

  5. input_line_20:2:2: error: no matching function for call to 'exit'
  6. exit()      但不幸的是,失败了,因为 exit 要求有一个参数。
  7. ^~~~
  8. /usr/include/stdlib.h:499:13: note: candidate function not viable: requires single argument '__status', but no arguments were provided
  9. extern void exit (int __status) __THROW __attribute__ ((__noreturn__));
  10.             ^
  11. user@ttyd:~$ 然而,看到没有?shell 提示符显示出来了!这说明已经成功退出 cish 了!为什么呢?因为自动进行了第三次尝试,加上参数 0,变成这样:exit(0) ——这当然能执行成功了,因为它是合法的 C 语句。这个语句执行完毕,当然就退出 cish 而回到 bash 的提示符了。
复制代码
回复

使用道具 举报

51#
 楼主| 发表于 2018-3-18 05:52:46 | 只看该作者
刚才只用 C 语言的 exit 函数,就退出了。那么,我们先前写好的 shell 内部命令 exit 就没有机会获得执行了。下面用 “歪门邪道”来执行内部命令 exit,即,在 exit 后面添加一个参数 #,即,非法参数。碰巧我们的内部命令能够容忍这个非法参数,因此,可以成功执行。


  1. [cling]$ exit #
  2. input_line_11:2:6: error: expected ';' after expression
  3. exit #           先用 C 解释,当然会失败。
  4.      ^
  5.      ;
  6. input_line_11:2:7: error: expected expression
  7. exit #
  8.       ^
  9. input_line_12:2:7: error: expected expression
  10. exit(#)          自动进行第二次尝试,加上括号,仍然失败。
  11.       ^
  12. input_line_13:2:2: error: no matching function for call to 'exit'
  13. exit("#")     自动进行第三次尝试,为参数加上引号,仍旧失败。
  14. ^~~~
  15. /usr/include/stdlib.h:499:13: note: candidate function not viable: no known conversion from 'const char [2]' to 'int' for 1st argument
  16. extern void exit (int __status) __THROW __attribute__ ((__noreturn__));
  17.             ^
  18. user@ttyd:~$
复制代码

看到 bash 提示符,知道是成功了。为什么能成功呢?因为自动进行了第四次尝试,交给 shell 模块来执行了。我们先前写的那个 shell 内部命令 exit 可以接受一个非法参数。这样就成功退回到 bash 了。
回复

使用道具 举报

52#
 楼主| 发表于 2018-3-18 12:02:26 | 只看该作者
本帖最后由 不点 于 2018-3-18 14:11 编辑

发现 Cling 的一个 bug:除以零时崩溃(core dumped)。

1/0 会正常报错,0/0 也会正常报错。这是因为编译器在编译阶段都能够发现分母为零,所以能够报错,不至于崩溃。

然而,

int k=0
0/k

这就崩溃了。说明 Cling 在运行时有 bug。

如果改成
0.0/k
1.0/k
1/(k+0.0)
都不会崩溃。这说明浮点计算很健壮,而整数计算不太完善。




----更新----

证明是 C 库函数有 bug,不是 Cling 的责任。

以下是 test.c 的内容,用 gcc test.c 或 g++ test.c 来编译,执行 ./a.out 它能成功打印出 OK!

但是,如果把浮点数 0.0 变成整数 0,则不能打印出 OK,而是显示 “浮点数异常”,程序崩溃了。

另外,崩溃时,它显示的信息也不准确。不应该显示 “浮点数异常”,而应该显示 “整数除以零错误”,或 “整数除法异常”。

这证明了问题的根源是库函数。



  1. #include <stdio.h>

  2. int
  3. main ()
  4. {
  5.         int k=0;

  6.         k = (k+0.0) / k;

  7.         printf ("OK!\n");
  8.         return 0;
  9. }
复制代码


回复

使用道具 举报

53#
发表于 2018-3-18 23:11:14 | 只看该作者
噢,又来瞧大师的工作了。。。很有趣。。。嗯,还氏先进行C解释,发现行不通再改为shell执行。

另,楼上大师说的那个除零问题报错,很可能的原因氏数据类型转换有关。
因为编译发x.y这样的形式,估计氏当作浮点数对待的。有可能0.0实际上变成了最小的浮点常量。

这样浮数和整数一齐做加法运算时,统统转为浮点。最后做除法,结果就报浮点出错啦。。。
回复

使用道具 举报

54#
 楼主| 发表于 2018-3-19 23:12:18 | 只看该作者
本帖最后由 不点 于 2018-3-20 13:51 编辑

记录一下。搜 “redirect stderr to stream c++” 找到:
https://stackoverflow.com/questions/5419356/redirect-stdout-stderr-to-a-string/24796475




庆祝一下。上述网页真棒!搞定了!把出错信息重定向到 stringstream 中,竟然如此简单!

cish 又上新台阶,这次真正调整过来了,即先按 C 解释,最后用 shell 解释。如果 shell 命令执行成功,则不显示出错信息。如果 shell 命令执行失败,则先显示 shell 出错信息,再显示 C 语言出错信息。

不过,目前在复合语句(if,switch,for,while 等结构)中暂不支持 shell 命令。目前只在 “简单语句(单行语句)” 的情况下才可以使用 shell 命令。



回复

使用道具 举报

55#
 楼主| 发表于 2018-3-21 17:21:10 | 只看该作者
本帖最后由 不点 于 2018-3-22 05:14 编辑

今天又改进了一点点,增加了一个功能,类似于别名。

用户自己首先建立如下函数(目前可以用键盘逐行敲入):


  1. int ll ( int argc, char **argv) {
  2.     system ("ls -l");
  3.     return 0;
  4. }
复制代码


然后,再敲入 ll 回车,就会执行 ls -l 命令。这只是一个演示,这个演示还没有用到 ll 的命令行参数 argcargv

下面是个带命令行参数的演示。这个函数 echo 能够打印出命令行参数:


  1. int echo (int argc, char **argv) {
  2.     for (int i=1; i<argc; i++) {
  3.         fputs(argv[i], stdout);
  4.         fputs(" ", stdout);
  5.     }
  6.     fputs("\n", stdout);
  7.     return 0;
  8. }
复制代码


运行效果:

  1. [cling]% int echo (int argc, char **argv) { for (int i=1; i<argc;i++){fputs(argv[i], stdout);fputs(" ", stdout);} fputs("\n", stdout);return 0;}
  2. [cling]% echo hjj    hjghjhjg    hjjgjghg
  3. hjj hjghjhjg hjjgjghg
  4. [cling]% echo
  5. [cling]% echo "hghghg  hjhjhj        hjhjhjhj"
  6. hghghg  hjhjhj        hjhjhjhj
  7. [cling]%
复制代码


这就有 echo 命令了。此时执行的是 echo 函数,而不是外部的 echo 命令。
要想执行外部命令 echo,可以敲入路径 /bin/echo 来执行。

一般来说,敲入一个不带路径的命令,则首先当作函数来运行。如果失败,则当作内部命令。如果仍然失败,最后才查找外部命令。


回复

使用道具 举报

56#
 楼主| 发表于 2018-3-22 17:19:31 | 只看该作者
本帖最后由 不点 于 2018-3-23 10:15 编辑

建立如下函数 ll,相当于建立 bash 的别名: alias ll="ls -alF --color=auto"

  1. int ll (int argc, char **argv) {
  2.         pid_t cpid, w;
  3.         int status = 0;
  4.         char * v[argc + 3]; /* end with NULL */
  5.         v[0] = (char *)"ls";
  6.         v[1] = (char *)"-alF";
  7.         v[2] = (char *)"--color=auto";
  8.         for (int i = 1; i < argc; i++) {
  9.                 v[i + 2] = argv[i];
  10.         }
  11.         v[argc + 2] = (char *) NULL; /* ending NULL */
  12.         cpid = fork();
  13.         if (cpid == 0) { // code executed by child
  14.                 execvp (v[0], v);
  15.                 perror ("execvp");
  16.                 printf ("Command not found: %s\n", v[0]);
  17.                 exit (-1); // exit child
  18.         }
  19.         // code executed by parent
  20.         if (cpid == -1) {
  21.                 perror ("fork");
  22.                 return 1;//exit (EXIT_FAILURE);
  23.         }
  24.         w = waitpid (cpid, &status, 0);
  25.         if (w == -1) {
  26.                 perror ("waitpid");
  27.                 return 1;//exit (EXIT_FAILURE);
  28.         }
  29.         return status;
  30. }
复制代码


把上述代码放在 $HOME/.cishrc 里面,就可以在每次启动 cish 后自动执行了。
回复

使用道具 举报

57#
发表于 2018-3-22 17:30:31 | 只看该作者
是个shell可以替换linux默认的shell吗?

点评

目前不能替换。自己试着玩可以。  详情 回复 发表于 2018-3-22 18:51
回复

使用道具 举报

58#
 楼主| 发表于 2018-3-22 18:51:41 | 只看该作者
jianliulin 发表于 2018-3-22 17:30
是个shell可以替换linux默认的shell吗?

目前不能替换。自己试着玩可以。
回复

使用道具 举报

59#
 楼主| 发表于 2018-3-23 11:27:52 | 只看该作者
目前我把主要精力用在真正需要的开发工作中,而不是分散一部分精力去做外围的项目管理工作。

等以后有了参与者、合伙人的时候,再考虑项目管理的问题。

说不定这个管理的工作,都不一定由我出面了。一切皆有可能。

比如说,有人建立 Web 主页,有人购买域名,有人负责写文档,有人负责代码优化整理,…… 那就真正活跃起来了。

目前只是个开头,也不需要考虑那么多的事情。
回复

使用道具 举报

60#
 楼主| 发表于 2018-3-23 15:38:10 | 只看该作者
做如下试验,定义 main 函数。执行时,崩溃了。原因可能是结尾缺少了 return 0;
  1. [cling]% int main () { printf("this is my main\n");}
  2. [cling]% main
  3. #0 0x000055eee06b4a4a (�8���U+0xa22a4a)
  4. #1 0x000055eee06b28d6 (�8���U+0xa208d6)
  5. #2 0x000055eee06b2a1c (�8���U+0xa20a1c)
  6. #3 0x00007fee99b52140 (/lib/x86_64-linux-gnu/libc.so.6+0x37140)
  7. #4 0x00007fee99c99f70 (/lib/x86_64-linux-gnu/libc.so.6+0x17ef70)
  8. #5 0x000055eee1263b51 (�8���U+0x15d1b51)
  9. #6 0x000055eee126b1f3 (�8���U+0x15d91f3)
  10. #7 0x000055eee062288e (�8���U+0x99088e)
  11. #8 0x000055eee061ae1a (�8���U+0x988e1a)
  12. #9 0x000055eee05016ef (�8���U+0x86f6ef)
  13. #10 0x00007fee9af45031
  14. #11 0x000055eee0619337 (�8���U+0x987337)
  15. #12 0x000055eee0619789 (�8���U+0x987789)
  16. #13 0x000055eee0619f67 (�8���U+0x987f67)
  17. #14 0x000055eee0664375 (�8���U+0x9d2375)
  18. #15 0x000055eee06df2bb (�8���U+0xa4d2bb)
  19. #16 0x000055eee0501d41 (�8���U+0x86fd41)
  20. #17 0x00007fee99b3c1c1 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x211c1)
  21. #18 0x000055eee0574eda (�8���U+0x8e2eda)
  22. Stack dump:
  23. 0.      Program arguments: /home/user/inst/bin/cling
  24. 1.      Program arguments: �8���U Segmentation fault (core dumped)
  25. user@ttyd:~$
复制代码


添上 return 0; 依旧崩溃(猜测可能是因为 main 的参数不对):

  1. user@ttyd:~$ cish
  2. [cling]$ int main () { printf("this is my main\n"); return 0;}
  3. [cling]% main
  4. #0 0x000055b4a5d25a4a (�H6��U+0xa22a4a)
  5. #1 0x000055b4a5d238d6 (�H6��U+0xa208d6)
  6. #2 0x000055b4a5d23a1c (�H6��U+0xa20a1c)
  7. #3 0x00007f4161dcd140 (/lib/x86_64-linux-gnu/libc.so.6+0x37140)
  8. #4 0x00007f4161f14f70 (/lib/x86_64-linux-gnu/libc.so.6+0x17ef70)
  9. #5 0x000055b4a68d4b51 (�H6��U+0x15d1b51)
  10. #6 0x000055b4a68dc1f3 (�H6��U+0x15d91f3)
  11. #7 0x000055b4a5c9388e (�H6��U+0x99088e)
  12. #8 0x000055b4a5c8be1a (�H6��U+0x988e1a)
  13. #9 0x000055b4a5b726ef (�H6��U+0x86f6ef)
  14. #10 0x00007f41631c0031
  15. #11 0x000055b4a5c8a337 (�H6��U+0x987337)
  16. #12 0x000055b4a5c8a789 (�H6��U+0x987789)
  17. #13 0x000055b4a5c8af67 (�H6��U+0x987f67)
  18. #14 0x000055b4a5cd5375 (�H6��U+0x9d2375)
  19. #15 0x000055b4a5d502bb (�H6��U+0xa4d2bb)
  20. #16 0x000055b4a5b72d41 (�H6��U+0x86fd41)
  21. #17 0x00007f4161db71c1 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x211c1)
  22. #18 0x000055b4a5be5eda (�H6��U+0x8e2eda)
  23. Stack dump:
  24. 0.      Program arguments: /home/user/inst/bin/cling
  25. 1.      Program arguments: �H6��U Segmentation fault (core dumped)
  26. user@ttyd:~$
复制代码


看下面的试验结果。参数加上了,这次不崩溃了。然而没有打印出 “this is my main”,这是为什么?
看到 main 执行后,下一行显示的提示符是 $ 而不是 %,这说明是执行了 cish 自身的 main 函数,因此它打印出它所认为的第一个提示符,即 $。接着执行 exit,希望退出内层的 main 子进程,结果,它直接退回到 bash 了。为什么?
因为执行 main 函数时,并未 fork 出一个子进程,而只不过是 call 了 main 函数罢了(仍然处于当前进程之中)。exit 命令当然就退出了目前的 cish 进程而返回到 bash。


  1. user@ttyd:~$ cish
  2. [cling]$ int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  3. [cling]% main
  4. [cling]$ exit
  5. user@ttyd:~$
复制代码


看下面的试验结果。这次不定义 main 了,而是用 extern 声明 main 是已有的函数。执行结果也是成功的,与上述说法是一致的。

  1. user@ttyd:~$ cish
  2. [cling]$ extern int main (int, char **);
  3. [cling]% main
  4. [cling]$ exit
  5. user@ttyd:~$
复制代码


好的,这次 extern 和 定义同时使用,结果也一样。

  1. user@ttyd:~$ cish
  2. [cling]$ extern int main (int, char **);
  3. [cling]% int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  4. [cling]% main
  5. [cling]$ exit
  6. user@ttyd:~$
复制代码


下面的试验——当两次定义 main 的时候,报错了。

  1. user@ttyd:~$ cish
  2. [cling]$ extern int main (int, char **);
  3. [cling]% int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  4. [cling]% int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  5. input_line_18:1:5: error: redefinition of 'main'
  6. int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  7.     ^
  8. input_line_17:1:5: note: previous definition is here
  9. int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  10.     ^
  11. [cling]% main
  12. [cling]$ exit
  13. user@ttyd:~$ cish
  14. [cling]$ int main (int, char **);
  15. [cling]% int main (int, char **);
  16. [cling]% int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  17. [cling]% int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  18. input_line_19:1:5: error: redefinition of 'main'
  19. int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  20.     ^
  21. input_line_18:1:5: note: previous definition is here
  22. int main (int argc, char **argv) { printf("this is my main\n"); return 0;}
  23.     ^
  24. [cling]% main
  25. [cling]$ exit
  26. user@ttyd:~$
复制代码


总结一下,内部的 main 函数早已存在,虽然再定义一个新的 main 函数也不报错,但这个后来者并未被承认。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2026-1-20 10:44

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表