Bash的24个陷阱分析

1. for i in `ls *.mp3`

常见的错误写法:

for i in `ls *.mp3`; do     # Wrong!

为什么错误呢?因为for...in语句是按照空白来分词的,包含空格的文件名会被拆 成多个词。如遇到 01 - Don‘t Eat the Yellow Snow.mp3 时,i的值会依次取 01,-,Don‘t,等等。

用双引号也不行,它会将ls *.mp3的全部结果当成一个词来处理。

for i in "`ls *.mp3`"; do   # Wrong!

正确的写法是

for i in *.mp3; do

2. cp $file $target

这句话基本上正确,但同样有空格 分词的问题。所以应当用双引号:

cp "$file" "$target"

但是如果凑巧文件名以 - 开头,这个文件名会被 cp 当作命令行选项来处理,依旧很头疼。可以试试下面这个。

cp -- "$file" "$target"

运气差点的再碰上一个不支持 -- 选项的系统,那只能用下面的方法了:使每个变量都以目录开头。

for i in ./*.mp3; do  cp "$i" /target  ...

3. [ $foo = "bar" ]

当$foo为空时,上面的命令就变成了

[ = "bar" ]

类似地,当$foo包 含空格时:

[ multiple words here = "bar" ]

两者都会出错。所以应当用双引号将变量括起来:

[ "$foo" = bar ]      # 几乎完美了。

但是!当$foo以 - 开头时依然会有问题。在较新的bash中你可以用下面的方法来代替,[[ 关键字能正确处理空白、空格、带横线等问题。

[[ $foo = bar ]]      # 正确

旧版本bash中可以用这个技巧(虽然不好理解):

[ x"$foo" = xbar ]    # 正确

或者干脆把变量放在右边,因为 [ 命令的等号右边即使是空白或是横线开头,依然能正常工作。(Java编程风格中也有类似的做法,虽然目的不一样。)

[ bar = "$foo" ]      # 正确

4. cd `dirname "$f"`

同样也存在空格问题。那么加上引号吧。

cd "`dirname "$f"`"

问题来了,是不是写错了?由于双引号的嵌套,你会认为`dirname 是第一个字符串,`是第二个字符串。错了,那是C语言。在bash中,命令替换(反引号``中的内容)里面的双引号会被正确地匹配到一起,不用特意去转 义。

$()语法也相同,如下面的写法是正确的。

cd "$(dirname "$f")"

5. [ "$foo" = bar && "$bar" = foo ]

[ 中不能使用 && 符号!因为 [ 的实质是 test 命令,&& 会把这一行分成两个命令的。应该用以下的写法。

[ bar = "$foo" -a foo = "$bar" ]       # Right![ bar = "$foo" ] && [ foo = "$bar" ]   # Also right![[ $foo = bar && $bar = foo ]]         # Also right!

6. [[ $foo > 7 ]]

很可惜 [[ 只适用于字符串,不能做数字比较。数字比较应当这样写:

(( $foo > 7 ))

或者用经典的写法:

[ $foo -gt 7 ]

但上述使用 -gt 的写法有个问题,那就是当 $foo 不是数字时就会出错。你必须做好类型检验。

这样写也行。

[[ $foo -gt 7 ]]

7. grep foo bar | while read line; do ((count++) ); done

由于格式问题,标题中我多加了一个空格。实际的代码应该是这 样的:

grep foo bar | while read line; do ((count++)); done         # 错误!

这行代码数出bar文件中包含foo的行数,虽然很麻烦(等同于grep -c foo bar或者 grep foo bar | wc -l)。乍一看没有问题,但执行之后count变量却没有值。因为管道中的每个命令都放到一个新的子shell中执行,所以子shell中定义的 count变量无法传递出来。

8. if [grep foo myfile]

初学者常犯的错误,就是将 if 语句后面的 [ 当作if语法的一部分。实际上它是一个命令,相当于 test 命令,而不是 if 语法。这一点C程序员特别应当注意。

if 会将 if 到 then 之间的所有命令的返回值当作判断条件。因此上面的语句应当写成

if grep foo myfile > /dev/null; then

9. if [bar="$foo"]

同样,[ 是个命令,不是 if 语句的一部分,所以要注意空格。

if [ bar = "$foo" ]

10. if [ [ a = b ] && [ c = d ] ]

同样的问题,[ 不是 if 语句的一部分,当然也不是改变逻辑判断的括号。它是一个命令。可能C程序员比较容易犯这个错误?

if [ a = b ] && [ c = d ]        # 正确

11. cat file | sed s/foo/bar/ > file

不能在同一条管道操作中同时读写一个文 件。根据管道的实现方式,file要么被截断成0字节,要么会无限增长直到填满整个硬盘。如果想改变原文件的内容,只能先将输出写到临时文件中再用mv命 令。

sed ‘s/foo/bar/g‘ file > tmpfile && mv tmpfile file

12. echo $foo

这句话还有什么错误码?一般来说是正确的,但下面的例子就有问题了。

MSG="Please enter a file name of the form *.zip"echo $MSG         # 错误!

如果恰巧当前目录下有zip文件,就会显示成

Please enter a file name of the form freenfss.zip lw35nfss.zip

所以即使是echo也别忘记给变量加引号。

13. $foo=bar

变 量赋值时无需加 $ 符号——这不是Perl或PHP。

14. foo = bar

变量赋值时等号两侧不能加空格——这不是C语言。

15. echo <<EOF

here document是个好东西,它可以输出成段的文字而不用加引号也不用考虑换行符的处理问题。不过here document输出时应当使用cat而不是echo。

# This is wrong:echo <<EOFHello worldEOF# This is right:cat <<EOFHello worldEOF

16. su -c ‘some command‘

原文的意思是,这条基本上正确,但使用者的目的是要将 -c ‘some command‘ 传给shell。而恰好 su 有个 -c 参数,所以su 只会将 ‘some command‘ 传给shell。所以应该这么写:

su root -c ‘some command‘

但是在我的平台上,man su 的结果中关于 -c 的解释为

-c, --commmand=COMMAND            pass a single COMMAND to the shell with -c

也就是说,-c ‘some command‘ 同样会将 -c ‘some command‘ 这样一个字符串传递给shell,和这条就不符合了。不管怎样,先将这一条写在这里吧。

17. cd /foo; bar

cd 有可能会出错,出错后 bar 命令就会在你预想不到的目录里执行了。所以一定要记得判断cd的返回值。

cd /foo && bar

如果你要根据cd的返回值执行多条命令,可以用 ||。

cd /foo || exit 1;barbaz

关于目录的一点题外话,假设你要在shell程序中频繁变换工作目录,如下面的 代码:

find ... -type d | while read subdir; do  cd "$subdir" && whatever && ... && cd -done

不如这样写:

find ... -type d | while read subdir; do  (cd "$subdir" && whatever && ...)done

括号会强制启动一个子shell,这样在这个子shell中改变工作目录不会影 响父shell(执行这个脚本的shell),就可以省掉cd - 的麻烦。

你 也可以灵活运用 pushd、popd、dirs 等命令来控制工作目录。

18. [ bar == "$foo" ]

[ 命令中不能用 ==,应当写成

[ bar = "$foo" ] && echo yes[[ bar == $foo ]] && echo yes

19. for i in {1..10}; do ./something &; done

& 后面不应该再放 ; ,因为 & 已经起到了语句分隔符的作用,无需再用;。

for i in {1..10}; do ./something & done

20. cmd1 && cmd2 || cmd3

有人喜欢用这种格式来代替 if...then...else 结构,但其实并不完全一样。如果cmd2返回一个非真值,那么cmd3则会被执行。所以还是老老实实地用 if cmd1; then cmd2; else cmd3 为好。

21. UTF-8的BOM(Byte-Order Marks)问题

UTF- 8编码可以在文件开头用几个字节来表示编码的字节顺序,这几个字节称为BOM。但Unix格式的UTF-8编码不需要BOM。多余的BOM会影响 shell解析,特别是开头的 #!/bin/sh 之类的指令将会无法识别。

MS-DOS格式的换行符(CRLF)也存在同样的问题。如果你将shell程序保存成DOS格式,脚本就无法执行了。

$ ./dos-bash: ./dos: /bin/sh^M: bad interpreter: No such file or directory

22. echo "Hello World!"

交互执行这条命令会产生以下的错误:

-bash: !": event not found

因为 !" 会被当作命令行历史替换的符号来处理。不过在shell脚本中没有这样的问题。

不幸的是,你无法使用转义符来转义!:

$ echo "hi\!"hi\!

解决方案之一,使用单引号,即

$ echo ‘Hello, world!‘

如果你必须使用双引号,可以试试通过 set +H 来取消命令行历史替换。

set +Hecho "Hello, world!"

23. for arg in $*

$*表示所 有命令行参数,所以你可能想这样写来逐个处理参数,但参数中包含空格时就会失败。如:

#!/bin/bash# Incorrect versionfor x in $*; do  echo "parameter: ‘$x‘"done$ ./myscript ‘arg 1‘ arg2 arg3parameter: ‘arg‘parameter: ‘1‘parameter: ‘arg2‘parameter: ‘arg3‘

正确的方法是使用 "[email protected]"。

#!/bin/bash# Correct versionfor x in "[email protected]"; do  echo "parameter: ‘$x‘"done$ ./myscript ‘arg 1‘ arg2 arg3parameter: ‘arg 1‘parameter: ‘arg2‘parameter: ‘arg3‘

在 bash 的手册中对 $* 和 [email protected] 的说明如下:

*    Expands to the positional parameters, starting from one.       When the expansion occurs within double quotes, it      expands to a single word with the value of each parameter      separated by the first character of the IFS special variable.       That is, "$*" is equivalent to "$1c$2c...",@    Expands to the positional parameters, starting from one.      When the expansion occurs within double quotes, each      parameter expands to a separate word.  That  is,  "[email protected]"       is equivalent to "$1" "$2" ...

可见,不加引号时 $* 和 [email protected] 是相同的,但"$*" 会被扩展成一个字符串,而 "[email protected]" 会被扩展成每一个参数。

24. function foo()

在bash中没有问题,但其他 shell中有可能出错。不要把 function 和括号一起使用。最为保险的做法是使用括号,即

foo() {  ...}

原帖:

http://tech.idv2.com/2008/01/09/bash-pitfalls/

感谢fcicq,他的new 30 days系列为我们带来了不少好文章。

今天想分析 的是这篇Bash Pitfalls, 介绍了一些bash编程中的经典错误。fcicq说可能不适合初学者,而我认为,正是bash编程的初学者才应该好好阅读一下这篇文章。

下 面就逐个分析一下这篇文章中提到的错误。不是完全的翻译,有些没用的话就略过了,有些地方则加了些注释。

1. for i in `ls *.mp3`

常见的错误写法:

for i in `ls *.mp3`; do     # Wrong!

为 什么错误呢?因为for...in语句是按照空白来分词的,包含空格的文件名会被拆成多个词。如遇到 01 - Don‘t Eat the Yellow Snow.mp3 时,i的值会依次取 01,-,Don‘t,等等。

用双引号也不行,它会将ls *.mp3的全部结果当成一个词来处理。

for i in "`ls *.mp3`"; do   # Wrong!

正 确的写法是

for i in *.mp3; do

2. cp $file $target

这句话 基本上正确,但同样有空格分词的问题。所以应当用双引号:

cp "$file" "$target"

但是如果凑巧文 件名以 - 开头,这个文件名会被 cp 当作命令行选项来处理,依旧很头疼。可以试试下面这个。

cp -- "$file" "$target"

运 气差点的再碰上一个不支持 -- 选项的系统,那只能用下面的方法了:使每个变量都以目录开头。

for i in ./*.mp3; do  cp "$i" /target  ...

3. [ $foo = "bar" ]

当$foo为空时,上面的命令就变成了

[ = "bar" ]

类 似地,当$foo包含空格时:

[ multiple words here = "bar" ]

两者都会出错。所以 应当用双引号将变量括起来:

[ "$foo" = bar ]      # 几乎完美了。

但是!当$foo以 - 开头时依然会有问题。在较新的bash中你可以用下面的方法来代替,[[ 关键字能正确处理空白、空格、带横线等问题。

[[ $foo = bar ]]      # 正确

旧 版本bash中可以用这个技巧(虽然不好理解):

[ x"$foo" = xbar ]    # 正确

或者干脆把 变量放在右边,因为 [ 命令的等号右边即使是空白或是横线开头,依然能正常工作。(Java编程风格中也有类似的做法,虽然目的不一样。)

[ bar = "$foo" ]      # 正确

4. cd `dirname "$f"`

同样也存在空格问题。那么加上引号吧。

cd "`dirname "$f"`"

问 题来了,是不是写错了?由于双引号的嵌套,你会认为`dirname 是第一个字符串,`是第二个字符串。错了,那是C语言。在bash中,命令替换(反引号``中的内容)里面的双引号会被正确地匹配到一起,不用特意去转 义。

$()语法也相同,如下面的写法是正确的。

cd "$(dirname "$f")"

5. [ "$foo" = bar && "$bar" = foo ]

[ 中不能使用 && 符号!因为 [ 的实质是 test 命令,&& 会把这一行分成两个命令的。应该用以下的写法。

[ bar = "$foo" -a foo = "$bar" ]       # Right![ bar = "$foo" ] && [ foo = "$bar" ]   # Also right![[ $foo = bar && $bar = foo ]]         # Also right!

6. [[ $foo > 7 ]]

很可惜 [[ 只适用于字符串,不能做数字比较。数字比较应当这样写:

(( $foo > 7 ))

或 者用经典的写法:

[ $foo -gt 7 ]

但上述使用 -gt 的写法有个问题,那就是当 $foo 不是数字时就会出错。你必须做好类型检验。

这样写也行。

[[ $foo -gt 7 ]]

7. grep foo bar | while read line; do ((count++) ); done

由于格式问题,标题中我 多加了一个空格。实际的代码应该是这样的:

grep foo bar | while read line; do ((count++)); done         # 错误!

这 行代码数出bar文件中包含foo的行数,虽然很麻烦(等同于grep -c foo bar或者 grep foo bar | wc -l)。乍一看没有问题,但执行之后count变量却没有值。因为管道中的每个命令都放到一个新的子shell中执行,所以子shell中定义的 count变量无法传递出来。

8. if [grep foo myfile]

初学者常犯的错误,就是将 if 语句后面的 [ 当作if语法的一部分。实际上它是一个命令,相当于 test 命令,而不是 if 语法。这一点C程序员特别应当注意。

if 会将 if 到 then 之间的所有命令的返回值当作判断条件。因此上面的语句应当写成

if grep foo myfile > /dev/null; then

9. if [bar="$foo"]

同样,[ 是个命令,不是 if 语句的一部分,所以要注意空格。

if [ bar = "$foo" ]

10. if [ [ a = b ] && [ c = d ] ]

同样的问题,[ 不是 if 语句的一部分,当然也不是改变逻辑判断的括号。它是一个命令。可能C程序员比较容易犯这个错误?

if [ a = b ] && [ c = d ]        # 正确

11. cat file | sed s/foo/bar/ > file

不能在同一条管道操作 中同时读写一个文件。根据管道的实现方式,file要么被截断成0字节,要么会无限增长直到填满整个硬盘。如果想改变原文件的内容,只能先将输出写到临时 文件中再用mv命令。

sed ‘s/foo/bar/g‘ file > tmpfile && mv tmpfile file

12. echo $foo

这句话还有什么错误码?一般来说是正确的,但下面的例子就有问题了。

MSG="Please enter a file name of the form *.zip"echo $MSG         # 错误!

如 果恰巧当前目录下有zip文件,就会显示成

Please enter a file name of the form freenfss.zip lw35nfss.zip

所 以即使是echo也别忘记给变量加引号。

13. $foo=bar

变量赋值时无需加 $ 符号——这不是Perl或PHP。

14. foo = bar

变量赋值时等号两侧不能加空格——这不是C语言。

15. echo <<EOF

here document是个好东西,它可以输出成段的文字而不用加引号也不用考虑换行符的处理问题。不过here document输出时应当使用cat而不是echo。

# This is wrong:echo <<EOFHello worldEOF# This is right:cat <<EOFHello worldEOF

16. su -c ‘some command‘

原文的意思是,这条基本上正确,但使用者的目的是要将 -c ‘some command‘ 传给shell。而恰好 su 有个 -c 参数,所以su 只会将 ‘some command‘ 传给shell。所以应该这么写:

su root -c ‘some command‘

但 是在我的平台上,man su 的结果中关于 -c 的解释为

-c, --commmand=COMMAND            pass a single COMMAND to the shell with -c

也 就是说,-c ‘some command‘ 同样会将 -c ‘some command‘ 这样一个字符串传递给shell,和这条就不符合了。不管怎样,先将这一条写在这里吧。

17. cd /foo; bar

cd 有可能会出错,出错后 bar 命令就会在你预想不到的目录里执行了。所以一定要记得判断cd的返回值。

cd /foo && bar

如 果你要根据cd的返回值执行多条命令,可以用 ||。

cd /foo || exit 1;barbaz

关于目录的 一点题外话,假设你要在shell程序中频繁变换工作目录,如下面的代码:

find ... -type d | while read subdir; do  cd "$subdir" && whatever && ... && cd -done

不 如这样写:

find ... -type d | while read subdir; do  (cd "$subdir" && whatever && ...)done

括 号会强制启动一个子shell,这样在这个子shell中改变工作目录不会影响父shell(执行这个脚本的shell),就可以省掉cd - 的麻烦。

你 也可以灵活运用 pushd、popd、dirs 等命令来控制工作目录。

18. [ bar == "$foo" ]

[ 命令中不能用 ==,应当写成

[ bar = "$foo" ] && echo yes[[ bar == $foo ]] && echo yes

19. for i in {1..10}; do ./something &; done

& 后面不应该再放 ; ,因为 & 已经起到了语句分隔符的作用,无需再用;。

for i in {1..10}; do ./something & done

20. cmd1 && cmd2 || cmd3

有人喜欢用这种格式来代替 if...then...else 结构,但其实并不完全一样。如果cmd2返回一个非真值,那么cmd3则会被执行。所以还是老老实实地用 if cmd1; then cmd2; else cmd3 为好。

21. UTF-8的BOM(Byte-Order Marks)问题

UTF-8编码可以在 文件开头用几个字节来表示编码的字节顺序,这几个字节称为BOM。但Unix格式的UTF-8编码不需要BOM。多余的BOM会影响shell解析,特别 是开头的 #!/bin/sh 之类的指令将会无法识别。

MS-DOS格式的换行符(CRLF)也存在同样的问题。如果你将shell程序 保存成DOS格式,脚本就无法执行了。

$ ./dos-bash: ./dos: /bin/sh^M: bad interpreter: No such file or directory

22. echo "Hello World!"

交互执行这条命令会产生以下的错误:

-bash: !": event not found

因 为 !" 会被当作命令行历史替换的符号来处理。不过在shell脚本中没有这样的问题。

不幸的是,你无法使用转义符来转义!:

$ echo "hi\!"hi\!

解 决方案之一,使用单引号,即

$ echo ‘Hello, world!‘

如果你必须使用双引号,可以试试通过 set +H 来取消命令行历史替换。

set +Hecho "Hello, world!"

23. for arg in $*

$*表示所有命令行参数,所以你可能想这样写来逐个处理参数,但参数中包含空格时就会失败。如:

#!/bin/bash# Incorrect versionfor x in $*; do  echo "parameter: ‘$x‘"done$ ./myscript ‘arg 1‘ arg2 arg3parameter: ‘arg‘parameter: ‘1‘parameter: ‘arg2‘parameter: ‘arg3‘

正 确的方法是使用 "[email protected]"。

#!/bin/bash# Correct versionfor x in "[email protected]"; do  echo "parameter: ‘$x‘"done$ ./myscript ‘arg 1‘ arg2 arg3parameter: ‘arg 1‘parameter: ‘arg2‘parameter: ‘arg3‘

在 bash 的手册中对 $* 和 [email protected] 的说明如下:

*    Expands to the positional parameters, starting from one.       When the expansion occurs within double quotes, it      expands to a single word with the value of each parameter      separated by the first character of the IFS special variable.       That is, "$*" is equivalent to "$1c$2c...",@    Expands to the positional parameters, starting from one.      When the expansion occurs within double quotes, each      parameter expands to a separate word.  That  is,  "[email protected]"       is equivalent to "$1" "$2" ...

可 见,不加引号时 $* 和 [email protected] 是相同的,但"$*" 会被扩展成一个字符串,而 "[email protected]" 会被扩展成每一个参数。

24. function foo()

在bash中没有问题,但其他shell中有可能出错。不要把 function 和括号一起使用。最为保险的做法是使用括号,即

foo() {  ...}
时间: 2024-10-14 00:57:20

Bash的24个陷阱分析的相关文章

【转】【C++专题】C++ sizeof 使用规则及陷阱分析

提示:下文例子都经过Visual C++ 6.0验证,平台为win32 Windows. 一.什么是sizeof 首先看一下sizeof在msdn上的定义: The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t. 看到

java中DelayQueue的一个使用陷阱分析

最近工作中有接触到DelayQueue,网上搜索资料的时候发现一篇文章谈到DelayQueue的坑.点击打开链接 文中已经总结了遇到坑的地方,还有解决方案.不过我第一眼看一下没弄明白为什么,所以翻了翻源码深究了一下,下面把这个坑的原因以及原理分析一下. 首先是DelayQueue的take()方法: 1 public E take() throws InterruptedException { 2 final ReentrantLock lock = this.lock; 3 lock.lock

C/C++ 知识点---sizeof使用规则及陷阱分析

原文:http://blog.csdn.net/chenqi514/article/details/7245273 1.什么是sizeof 首先看一下sizeof在msdn上的定义:     The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value o

Bash远程代码执行漏洞分析

 今日爆出一个Bash的RCE漏洞,威力巨大.看了看老外的分析,觉得有必要写一写自己对这个漏洞的理解. 首先,问题起因于一个命令ENV. 原型: env [OPTION]... [NAME=VALUE]... [COMMAND [ARGS]...] Man是这么说的: Display, set, or remove environment variables,Run a command in a modified environment. 我的理解是使用env命令的key=value,首先会

表达式中的陷阱(分析)

运算符:java中预定义的进行某种特殊运算符号 // + — && <<表达式1.表达式是一种运算符和操作数合成在一 起组成的式子运算符需要的操作数数量不相同,a+b a*b a++ ?:运算符需要的操作数类型别不相同 a+b A+1 1+1 2.表达式都有一个结果 习题: (一). int a = 10: int b = a+(a=5)+a+(a=10); 分析: 10+(a=5)+a+(a=10) a=10 10+5+a+(a=10) a=5 10+5+5+(a=10) a

list遍历陷阱分析原理

35.Arraylist 的动态扩容机制是如何自动增加的?简单说说你理解的增加流程! 解析: 当在 ArrayList 中增加一个对象时 Java 会去检查 Arraylist 以确保已存在的数组中有足够的容量来存储这个新对象,如果没有足够容量就新建一个长度更长的数组(原来的1.5倍),旧的数组就会使用 Arrays.copyOf 方法被复制到新的数组中去,现有的数组引用指向了新的数组.下面代码展示为 Java 1.8 中通过 ArrayList.add 方法添加元素时,内部会自动扩容,扩容流程

2019.7.24 校内测试 分析+题解

T1 地雷 题目很简单呢,就是求哪个数只出现了一次就可以了哦~ 我一开始的想法是桶排(这也是最单纯最简单的想法吧~),但是空间开 232 肯定会炸的,而且时间好像也会炸掉. 然后左边的 ych 大佬小声说了一句:“得换个算法.” 嗯,确实要换个算法,然后我就觉得新算法一定是不用开数组,直接输完数据就能出答案的那种! 然后不知道怎么就想到了 zhx 讲博弈论的时候输入的同时将 ……(一些稀奇古怪的东西) 异或起来就是答案,这不正好跟我理想的新算法很像嘛? 异或异或?咦,又想到了六月底那次考试有个叫

中断分析

MINIX3 中断机制源码分析 下面我们来探讨下 MINIX 中断处理函数的具体处理流程: 由前面的章节知道,MINIX 的架构是标准的微内核结构,除了时钟中断处理程 序可以直接在内核态进行,其他的都只能从用户态,用户态像内核态发送消息. 假设我们是一个内核设计者,怎么能够将这种机制实现呢?我们会在系统任务里 设置一个中断注册调用,通过那个调用,我们能够将用户需要的中断处理函数挂 15 到相应的地方并且以后能够被用户识别. 现在继续往下面分析:我们现在又 16 根通用的中断地址,但是这是不够的,

从 A/Looper: Could not create epoll instance. errno=24 错误浅谈解决各种 bug 的思路

今天代码写着写着就莫名闪退了,手机也没有“程序停止运行”的提示,logcat也没有看到蓝色的调用栈log,这样的闪退最是蛋疼了,还好必现.复现几次之后,终于从logcat中看到了一行可疑的log: A/Looper: Could not create epoll instance. errno=24 ,看起来又是在native层闪退了.本文就把这个问题的分析解决过程记录了下来. 方法论 遇见没填过的坑,第一反应就是Google之,果然前几个结果中一个 Stack Overflow的问答 就为这个