Shell Makefile 中的符号

本文详细介绍了Shell脚本中常见的特殊符号及其用法,包括大括号{}
hell脚本中一些特殊符号
1、{} 大括号:
用法一:通配符扩展
代码: 
ls my_{finger,toe}s
这条命令相当于如下命令的组合:
代码: 
ls my_fingers my_toes
mkdir {userA,userB,userC}-{home,bin,data}
我们将得到 userA-home, userA-bin, userA-data, userB-home, userB-bin,userB-data,userC-home, userC-bin, userC-data,这几个目录
用法二:可用于语句块的构造,语句之间用回车隔开。如果你想在某些使用单个语句的地方(比如在AND或OR列表中)使用多条语句,你可以把它们括在花括号{}中来构造一个语句块。
代码: 
grep -v "$cdcatnum" $strack_file > $temp_file
cat $temp_file > $strack_file
echo
cat -n file1
(注:以上大括号中的四句命令够成了一个语句块)
用法三:参数扩展
代码: 
${name:-default} 使用一个默认值(一般是空值)来代替那些空的或者没有赋值的变量name;
${name:=default}使用指定值来代替空的或者没有赋值的变量name;
${name:?message}如果变量为空或者未赋值,那么就会显示出错误信息并中止脚本的执行同时返回退出码1。
${#name} 给出name的长度
${name%word} 从name的尾部开始删除与word匹配的最小部分,然后返回剩余部分
${name%%word} 从name的尾部开始删除与word匹配的最长部分,然后返回剩余部分
${name#word} 从name的头部开始删除与word匹配的最小部分,然后返回剩余部分
${name##word} 从name的头部开始删除与word匹配的最长部分,然后返回剩余部分
(注,name为变量名,word为要匹配的字符串)
用法三在处理字符串和未知变量时,是很有用的。
2、[] 中括号: 
用法一:通配符扩展:
允许匹配方括号中任何一个单个字符
代码: 
ls /[eh][to][cm]*
相当于执行 ls /etc /home(若有/eom目录,就相当于会执行ls /etc /home /eom)
注:在mkdir命令下不能扩展
用法二:用于条件判断符号:
[]符号可理解为指向test命令的一个软链接,所以其用法可完全参照test,将test位置替换为[便可。
代码: 
if [ "$?" != 0 ] 等价于 if test "$?" != 0
then echo "Executes error"

3、`command` 反引号:
`command`与$(command)的含义相同,都是返回当前执行命令的结果
代码: 
#!/bin/sh
for file in $(ls f*.sh);do
    lpr $file
done
exit 0
该例实现了扩展f*.sh给出所有匹配模式的文件的名字。
4、'string' 单引号 和 "string" 双引号 
双引号:如果想在定义的变量中加入空格,就必须使用单引号或双引号,
单、双引号的区别在于双引号转义特殊字符而单引号不转义特殊字符
代码: 
$ heyyou=home
$ echo '$heyyou'
$ $heyyou ($没有转义)
eg: $ heyyou=home
$ echo "$heyyou"
$ home (很明显,$转义了输出了heyyou变量的值)

5、$# 它的作用是告诉你引用变量的总数量是多少;
代码: 
$$ 它的作用是告诉你shell脚本的进程号;
$* 以一个单字符串显示所有的脚本传递的参数。等价于$1 $2 $3.......;
$@ 与$*基本类似(参见序号7),但在数组赋值时有些不同;
$? 前一个命令的退出码;
$- 显示shell使用的当前选项;
$! 最后一个后台运行的进程ID号。

6、$((...))语法:对括号内的表达式求值
代码: 
#!/bin/sh
x=0
hile [ "$x" -ne 10 ];do
echo $x
x=$(($x+1))
done
exit 0

7、shell中几种特殊的参数变量的引用
代码: 
$1、$2、$3……${10}、${11}、${12}…… :表示脚本传入的的各个参数,注意当需表示两位数以后的参数时数字要用花括号括起。
$@ 列出所有的参数,各参数用空格隔开
$*: 列出所有的参数,各参数用环境变量IFS的第一个字符隔开

8、命令列表: 
AND列表 statement1 && statement2 && statement3 && …:只有在前面所有的命令都执行成功的情况下才执行后一条命令
OR列表 statement1 || statement2 || statement3 || …:允许执行一系列命令直到有一条命令成功为止,其后所有命令将不再被执行
#!/bin/sh
代码: 
touch file_one
rm -f file_two
if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo " there"
then
echo "in if"
else
echo "in else"
fi
exit 0
上例的输出为:
代码: 
hello
in else
关于AND列表与OR列表,在逻辑判断中很使用,下面就举一个其最常用的例子:
代码: 
[ condition ] && command for true || command for false:
当条件为真时,执行commandfor true ,当条件为假时,执行command for false
9、: 冒号:内建空指令,返回值为0
代码: 
$ :
$ echo $?
$ 0
while: (该语句结构可实现一个无限循环)

10、; 分号: 在 shell 中,担任"连续指令"功能的符号就是"分号"
代码: 
cd ~/backup ; mkdir startup ; cp ~/.* startup/.

11、# 井号:表示符号后面的是注解文字,不会被执行;
代码: 
* 匹配文件名中的任何字符,包括字符串;
? 匹配文件名中的任何单个字符。
~ 代表使用者的 home 目录

12、/ 倒斜线:
放在指令前,有取消 aliases(别名) 的作用;
放在特殊符号前,则该特殊符号的作用消失;
放在指令的最末端,表示指令连接下一行(使得回车符无效,只起换行作用)
13、! 感叹号:
通常它代表反逻辑的作用,譬如条件侦测中,用 != 来代表"不等于"
14、** 次方运算:两个星号在运算时代表 "次方" 的意思
代码: 
let "sus=2**3"
echo "sus = $sus"
$ sus = 8 -

====
http://blog.youkuaiyun.com/linphusen/article/details/6557471
<think>我们正在讨论在Makefile中执行shell语句的方法。根据用户的问题和之前的引用,我们需要总结几种在Makefile中执行shell命令的方式,并注意其中的细节。 引用中提到了几种方法: 1. 在规则(rule)的命令部分直接写shell命令(引用[1]和引用[3])。 2. 使用`$(shell ...)`函数(引用[2]和引用[4])。 3. 注意多行命令的连接(使用分号或斜杠)以及变量传递(引用[3]和引用[5])。 下面我们详细说明: 方法1:在规则中直接写shell命令 Makefile的规则由目标、依赖和命令组成。在命令部分,每行命令都会在一个独立的shell进程中执行(默认是/bin/sh)。因此,如果需要多个命令在同一shell进程中执行(例如,前一个命令影响后一个命令的环境),则需要使用斜杠(\)将多行命令连接成一行,或者用分号(;)分隔多个命令。 示例: ```makefile target: command1 ; command2 # 用分号分隔,在同一行执行 command3 && command4 # 如果command3成功则执行command4 ``` 或者多行用斜杠连接: ```makefile target: command1 && \ command2 ``` 注意:Makefile中每行命令前必须以Tab开头(除非设置了使用其他前缀)。 方法2:使用`$(shell ...)`函数 这个函数可以在Makefile的任意位置执行shell命令,并将命令的输出作为函数的返回值(类似于命令替换)。这个函数会创建一个新的shell进程来执行命令。 示例: ```makefile # 获取当前目录下所有文件 FILES := $(shell ls) # 获取当前路径 CURRENT_PATH := $(shell pwd) # 条件判断:如果文件不存在则创建 # 注意:这里使用分号将多个命令组合在一起,因为整个$(shell ...)是一个函数调用,只能接受一个字符串作为命令。 FILE_CHECK := $(shell if [ ! -f abc ]; then touch abc; fi) ``` 注意:使用`$(shell ...)`函数时,要特别注意性能问题,因为每次调用都会启动新的shell进程(引用[4])。另外,函数中的命令会立即执行(在解析Makefile时),而不是在规则执行时。 方法3:在规则中使用shell语法 在规则的命令部分,可以使用shell的条件判断、循环等。但要注意,Makefile会将`$`符号视为变量引用的开始,因此如果要使用shell变量,需要使用两个`$$`。 示例:在规则中使用条件判断 ```makefile check: if [ -f file.txt ]; then \ echo "File exists"; \ else \ echo "File does not exist"; \ fi ``` 这里,整个if语句被写成一个命令(通过斜杠连接多行),所以在一个shell进程中执行。 注意事项: - 如果命令中需要用到shell变量,必须使用双美元符号($$)来转义,例如`$$HOME`(引用[5])。 - Makefile的变量(使用`$(VAR)`或`${VAR}`)在shell命令中会被展开,因此如果需要在shell命令中使用真正的shell变量,需要转义`$`。 - 不同的shell可能语法略有不同,Makefile默认使用`/bin/sh`(可能不是bash),所以尽量使用POSIX shell语法。 下面我们通过一个综合示例来展示这些方法: 示例Makefile: ```makefile # 使用shell函数获取文件列表(在解析阶段执行) FILES := $(shell ls) # 默认目标 all: check show_files # 目标:检查文件是否存在 check: @if [ -f Makefile ]; then \ echo "Makefile exists"; \ else \ echo "Makefile not found"; \ fi # 目标:显示文件列表 show_files: @echo "Files: $(FILES)" # 目标:创建一个文件(使用条件命令) create_file: @if [ ! -f newfile ]; then \ touch newfile; \ echo "Created newfile"; \ else \ echo "newfile already exists"; \ fi clean: rm -f newfile ``` 说明: - 目标`check`和`create_file`中的命令前面有`@`,这表示不显示命令本身,只显示输出。 - 变量`FILES`在Makefile解析阶段就被赋值,所以它在整个Makefile中都是可用的。 注意事项(引用[4]): 大量使用`$(shell ...)`函数会影响性能,因为每调用一次就启动一个shell进程。 综上所述,在Makefile中执行shell命令主要有两种场景: 1. 在规则的命令部分直接写shell命令(当需要根据依赖关系执行命令时)。 2. 使用`$(shell ...)`函数(当需要在解析Makefile时获取信息,或者定义变量时)。 请根据实际需求选择合适的方法。 根据用户要求,生成相关问题: §§相关问题§§ 1. Makefile中如何避免多次调用`$(shell ...)`函数导致的性能问题? 2. 在Makefile的规则中,如何正确使用循环结构? 3. Makefile中如何传递环境变量到shell命令? </think>### Makefile 中执行 Shell 语句的方法详解 在 Makefile 中执行 Shell 语句主要有两种方式,需特别注意语法差异和执行时机。以下是核心方法及示例: --- #### 1. **在规则命令中直接执行 Shell 语句** 在 Makefile 的规则命令块(以 `Tab` 开头)中直接写入 Shell 命令,每行命令会在独立的子 Shell 中执行。 **语法特点**: - 使用 `; \` 连接多行命令(斜杠后不能有空格) - `$` 需转义为 `$$`(否则会被当作 Makefile 变量) - 命令默认输出到终端,可用 `@` 前缀抑制输出 **示例**: ```makefile target: @echo "开始执行Shell命令" # 抑制输出的命令 if [ -f file.txt ]; then \ echo "文件存在"; \ else \ touch file.txt; \ fi echo "当前路径: $$PWD" # 转义$获取Shell变量 ``` **执行结果**: ```bash 开始执行Shell命令 文件存在 # 或执行 touch file.txt 当前路径: /home/project ``` > 此方法适用于依赖目标/文件的场景(如编译规则)[^1][^3] --- #### 2. **使用 `$(shell ...)` 函数** 在 Makefile 的 **变量赋值** 或 **函数调用** 中执行 Shell 命令,结果可保存到变量。 **语法特点**: - 命令在 Makefile **解析阶段立即执行**(非运行时) - 支持嵌套调用和多命令组合 - 需避免在复杂规则中过度使用(性能损耗)[^4] **示例**: ```makefile # 获取系统信息(解析阶段执行) FILES := $(shell ls) # 保存文件列表到变量 TIME_NOW := $(shell date +%F) # 条件创建文件(使用命令组合) CHECK_FILE := $(shell \ if [ ! -f log.txt ]; then \ touch log.txt; \ echo "created"; \ else \ echo "exists"; \ fi \ ) print: @echo "文件列表: $(FILES)" @echo "检查结果: $(CHECK_FILE)" @echo "当前时间: $(TIME_NOW)" ``` **执行效果**: ```bash $ make print 文件列表: Makefile file.txt ... 检查结果: exists # 或 created 当前时间: 2023-08-20 ``` > 此方法适合获取系统状态、预计算路径等[^2][^4] --- #### ️ **关键注意事项** 1. **变量作用域** - `$(shell ...)` 内定义的 Shell 变量 **不会** 传递到外部 Shell ```makefile # 错误示例(变量作用域隔离) VAR := $(shell data="hello"; echo $$data) # 输出空[^5] ``` 2. **执行时机差异** - `$(shell ...)` 在 Makefile 解析阶段执行 - 规则命令在 `make` 运行时执行 3. **特殊字符转义** - 括号 `()` 等需转义:`if [ \( "x" = "x" \) ]` 4. **换行符问题** Windows 换行符(`\r\n`)会导致语法错误,需转换为 Unix 格式(`\n`): ```bash dos2unix Makefile # 转换工具 ``` --- #### 完整综合示例 ```makefile # 解析阶段:获取内核版本(立即执行) KERNEL_VER := $(shell uname -r) # 运行时:编译并备份 build: clean @echo "内核版本: $(KERNEL_VER)" # 使用预计算的变量 gcc -o app main.c @if [ -f app ]; then \ cp app /backup/app_$$(date +%s); \ # 转义$获取运行时时间戳 fi clean: rm -f app ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值