Blog:博客园 个人

译自BashPitfalls

本文总结了编写Shell脚本中的常见错误。

for f in $(ls *.mp3)

最常犯的错之一就是编写这样的循环:

for f in $(ls *.mp3); do    # Wrong!
some command $f # Wrong!
done for f in $(ls) # Wrong!
for f in `ls` # Wrong! for f in $(find . -type f) # Wrong!
for f in `find . -type f` # Wrong! files=($(find . -type f)) # Wrong!
for f in ${files[@]} # Wrong!

确实,如果可以将ls的输出或者find作为文件名列表并对其进行迭代,看起来确实没啥问题。但是,这类方法是有缺陷的。

比如:

  • 如果文件名包含空格,for循环会将空格也分割(默认IFS为空格、\n、``\t),例如01 - Don't Eat the Yellow Snow.mp3,for循环会分割成01、 -、 Don't、Eat、 the、Yellow、Snow.mp3`。
  • 如果文件名包含glob字符(例如*),包含它的单词将被识别为模式并用与其匹配的所有文件名列表替换。
  • 如果命令替换返回多个文件名,则无法区分第一个文件名的结束位置和第二个文件名的开始位置。路径名可以包含除NUL之外的任何字符。是的,这包括换行符。
  • ls实用程序可能会损坏文件名。根据您使用的平台、使用(或未使用)的参数以及其标准输出是否指向终端,ls可能会随机决定将文件名中的某些字符替换为“?”,或者干脆不打印它们。永远不要尝试解析ls的输出。ls完全是不必要的。它是一个外部命令,其输出专门供人读取,而不是由脚本解析。
  • 命令替代(Command Substitution)从其输出中剥离所有尾随换行符。这看起来可能是可取的,因为ls添加了一个换行符,但是如果列表中的最后一个文件名以换行符结束,则命令替代会删除换行符。

正确做法:

for file in ./*.mp3; do    # Better! and…
some command "$file" # …always double-quote expansions!
done

cp $file $target

如果 $file和$target中有空格(如果没有修改$IFS),cp $file $target执行会报错,例如复制文件01 - Don't Eat the Yellow Snow.mp3到/mn/usb:

cp 01 - Don't Eat the Yellow Snow.mp3 /mnt/usb

会报以下错误:

cp: cannot stat ‘01’: No such file or directory
cp: cannot stat ‘-’: No such file or directory
cp: cannot stat ‘Don't’: No such file or directory
cp: cannot stat ‘Eat’: No such file or directory
cp: cannot stat ‘the’: No such file or directory
cp: cannot stat ‘Yellow’: No such file or directory
cp: cannot stat ‘Snow.mp3’: No such file or directory

正确做法:

cp -- "$file" "$target"

强烈建议:引用变量的时候,一定要加双引号。

Filenames with leading dashes

如果文件名带有-,命令可能错误把它当作参数。

解决的方法之一是,在变量前面加--,例如:

cp -- "$file" "$target"

加--是告诉命令,停止扫描参数。

注意:此方法的潜在问题,必须确保每条命令都要插入--,这很容易遗漏。

还有一种方法是使用相对路径或者绝对路径。例如:

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

在这种情况下,即使开头包含-的文件,也可以确保变量始终包含类似./-foo.mp3的文件,这样就比较安全。

[ $foo = "bar" ]

如果[中引用的变量不存在或为空,则[命令最终将如下所示:

[ = "bar" ] # Wrong!

Tips:=是二元一次运算符,不是一元一次运算符。

如果变量包含内部空格,则会在[命令看到它之前将其拆分成单独的单词,例如:

[ multiple words here = "bar" ]

看起来没啥问题,但在[]语法中是错误的,正确方式是加上双引号:

# POSIX
[ "$foo" = bar ] # Right! # Bash / Ksh
[[ $foo == bar ]] # Right!

cd $(dirname "$f")

这也是引用错误。正确做法:

cd -P -- "$(dirname -- "$f")"

Tips:-p参数是递归处理,将指定目录下的所有文件与子目录一并处理。

Shell:常见错误总结(一)的更多相关文章

  1. (转)Hadoop之常见错误集锦

     Hadoop之常见错误集锦            下文中没有特殊说明,环境都是CentOS下Hadoop 2.2.0.1.伪分布模式下执行start-dfs.sh脚本启动HDFS时出现如下错误:   ...

  2. Shell常见用法小记

    shell的简单使用 最近发现shell脚本在平常工作中简直算一把瑞士军刀,很多场景下用shell脚本能实现常用的简单需求,而之前都没怎么学习过shell,就趁机把shell相关的语法和常见用法总结了 ...

  3. Elasticsearch 集群和索引健康状态及常见错误说明

    之前在IDC机房线上环境部署了一套ELK日志集中分析系统, 这里简单总结下ELK中Elasticsearch健康状态相关问题, Elasticsearch的索引状态和集群状态传达着不同的意思. 一.  ...

  4. centos linux 系统日常管理4 scp,rsync,md5sum,sha1sum,strace ,find Rsync 常见错误及解决方法 第十七节课

    centos linux 系统日常管理4  scp,rsync,md5sum,sha1sum,strace ,find Rsync 常见错误及解决方法  第十七节课 rsync可以增量同步,scp不行 ...

  5. hadoop常见错误总结三

    问题导读:1.... could only be replicated to 0 nodes, instead of 1 ...可能的原因是什么?2.Error: java.lang.NullPoin ...

  6. 解决hadoop 集群启动常见错误办法

    hadoop 集群常见错误解决办法 hadoop 集群常见错误解决办法: (一)启动Hadoop集群时易出现的错误: 1.   错误现象:Java.NET.NoRouteToHostException ...

  7. hadoop 集群常见错误解决办法

    hadoop 集群常见错误解决办法 hadoop 集群常见错误解决办法: (一)启动Hadoop集群时易出现的错误: 1.   错误现象:Java.NET.NoRouteToHostException ...

  8. Git学习之常见错误 clone被拒绝

    Git学习之常见错误 问题: git clone 时 报错 Permission Denied (权限被拒绝). 解决方法: 需要把本地的公钥上传到服务器. 解决步骤: ①第一步,设置本地的git的用 ...

  9. 笔记:npm常见错误

    常见错误 破坏的npm安装 随机错误 找不到兼容版本 权限错误 Error: ENOENT, stat 'C:\Users\<user>\AppData\Roaming\npm' 在Win ...

随机推荐

  1. Solution -「CodeChef JUMP」Jump Mission

    \(\mathcal{Description}\)   Link.   有 \(n\) 个编号 \(1\sim n\) 的格子排成一排,并有三个权值序列 \(\{a_n\},\{h_n\},\{p_n ...

  2. Redis小秘密

    Redis小秘密 临渊羡鱼,不如退而织网. 一.Redis基本数据类型 想必很多人都能脱口而出String.List.Hash.Sorted Set和Set五种基本数据类型. 以及五大基本数据类型简要 ...

  3. Spring AOP应用之一:声明式事务

    所有数据访问技术都提供事务处理机制,这些技术提供了API用来开启事务.提交事务完成数据操作,或者在发生错误的时候回滚数据.Spring本身并不支持事务实现,同时只是负责提供标准接口来处理不同数据访问技 ...

  4. 看SparkSql如何支撑企业数仓

    企业级数仓架构设计与选型的时候需要从开发的便利性.生态.解耦程度.性能. 安全这几个纬度思考.本文作者:惊帆 来自于数据平台 EMR 团队 前言 Apache Hive 经过多年的发展,目前基本已经成 ...

  5. shell切割nginx日志

    用linux自带的计划任务切割nginx日志,每天0点执行 #!/bin/bash #GuoYabin nginxpid=`/bin/ps aux|grep nginx |awk /master/'{ ...

  6. HTML表格总结

    知识小记: 表格的主要目的:用于HTML展示数据,不适用于布局. 表格由行的单元格组成,没有列,常识上的"列"的个数取决于行中单元格的个数. 表格本来就很丑,颜色线条美化交给css ...

  7. 微服务从代码到k8s部署应有尽有系列(八、各种队列)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  8. 华为eNSP的防火墙(USG6000V)如何使用Web界面登入

    文章目录 华为eNSP的防火墙(USG6000V)如何使用Web界面登入 前言 一.使用步骤 1.导入USG6000V的镜像包 总结 前言 在华为的eNSP的模拟器上如何使用Web界面去管理与使用模拟 ...

  9. 当TIME_WAIT状态的TCP正常挥手,收到SYN后…

    摘要:今天就来讨论下这个问题,在TCP正常挥手过程中,处于TIME_WAIT状态的连接,收到相同四元组的SYN后会发生什么? 本文分享自华为云社区<在TIME_WAIT状态的TCP连接,收到SY ...

  10. Hadoop - 入门学习笔记(详细)

    目录 第1章 大数据概论 第2章 从Hadoop框架讨论大数据生态 第3章 Hadoop运行环境搭建(开发重点) 第4章 Hadoop运行模式 本地模式:默认配置 伪分布式模式:按照完全分布式模式配置 ...