$(( )) 與 $( ) 還有${ } 差在哪

8) $(( )) 與 $( ) 還有${ } 差在哪? 

我們上一章介紹了 ( ) 與 { } 的不同,這次讓我們擴展一下,看看更多的變化:$( ) 與 ${ } 又是啥玩意兒呢?

在 bash shell 中,$( ) 與 ` ` (反引號) 都是用來做命令替換用(command substitution)的。
所謂的命令替換與我們第五章學過的變量替換差不多,都是用來重組命令行:
* 完成引號裡的命令行,然後將其結果替換出來,再重組命令行。
例如:
  1. $ echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)
复制代码

如此便可方便得到上一星期天的日期了... ^_^

在操作上,用 $( ) 或 ` ` 都無所謂,只是我"個人"比較喜歡用 $( ) ,理由是:

1,  ` ` 很容易與 ' ' ( 單引號)搞混亂,尤其對初學者來說。
有時在一些奇怪的字形顯示中,兩種符號是一模一樣的(直豎兩點)。
當然了,有經驗的朋友還是一眼就能分辯兩者。只是,若能更好的避免混亂,又何樂不為呢? ^_^

2, 在多層次的復合替換中,` ` 須要額外的跳脫( \` )處理,而 $( ) 則比較直觀。例如:
這是錯的:
  1. command1 `command2 `command3` `
复制代码

原本的意圖是要在 command2 `command3` 先將 command3 提換出來給 command 2 處理,
然後再將結果傳給 command1 `command2 ...` 來處理。
然而,真正的結果在命令行中卻是分成了 `command2 ` 與 `` 兩段。
正確的輸入應該如下:
  1. command1 `command2 \`command3\` `
复制代码


要不然,換成 $( ) 就沒問題了:
  1. command1 $(command2 $(command3))
复制代码

只要你喜歡,做多少層的替換都沒問題啦~~~  ^_^

不過,$( ) 並不是沒有斃端的...
首先,` ` 基本上可用在全部的 unix shell 中使用,若寫成 shell script ,其移植性比較高。
而 $( ) 並不見的每一種 shell 都能使用,我只能跟你說,若你用 bash2 的話,肯定沒問題...  ^_^

接下來,再讓我們看 ${ } 吧... 它其實就是用來作變量替換用的啦。
一般情況下,$var 與 ${var} 並沒有啥不一樣。
但是用 ${ } 會比較精確的界定變量名稱的範圍,比方說:
  1. $ A=B
  2. $ echo $AB
复制代码

原本是打算先將 $A 的結果替換出來,然後再補一個 B 字母於其後,
但在命令行上,真正的結果卻是只會提換變量名稱為 AB 的值出來...
若使用 ${ } 就沒問題了:
  1. $ echo ${A}B
  2. BB
复制代码


不過,假如你只看到 ${ } 只能用來界定變量名稱的話,那你就實在太小看 bash 了﹗
有興趣的話,你可先參考一下 cu 本版的精華文章:
http://www.chinaunix.net/forum/viewtopic.php?t=201843

為了完整起見,我這裡再用一些例子加以說明 ${ } 的一些特異功能:
假設我們定義了一個變量為:
file=/dir1/dir2/dir3/my.file.txt
我們可以用 ${ } 分別替換獲得不同的值:
${file#*/}:拿掉第一條 / 及其左邊的字串:dir1/dir2/dir3/my.file.txt
${file##*/}:拿掉最後一條 / 及其左邊的字串:my.file.txt
${file#*.}:拿掉第一個 .  及其左邊的字串:file.txt
${file##*.}:拿掉最後一個 .  及其左邊的字串:txt
${file%/*}:拿掉最後條 / 及其右邊的字串:/dir1/dir2/dir3
${file%%/*}:拿掉第一條 / 及其右邊的字串:(空值)
${file%.*}:拿掉最後一個 .  及其右邊的字串:/dir1/dir2/dir3/my.file
${file%%.*}:拿掉第一個 .  及其右邊的字串:/dir1/dir2/dir3/my
記憶的方法為:
  • # 是去掉左邊(在鑑盤上 # 在 $ 之左邊)
    % 是去掉右邊(在鑑盤上 % 在 $ 之右邊)
    單一符號是最小匹配﹔兩個符號是最大匹配。

${file:0:5}:提取最左邊的 5 個字節:/dir1
${file:5:5}:提取第 5 個字節右邊的連續 5 個字節:/dir2

我們也可以對變量值裡的字串作替換:
${file/dir/path}:將第一個 dir 提換為 path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:將全部 dir 提換為 path:/path1/path2/path3/my.file.txt

利用 ${ } 還可針對不同的變數狀態賦值(沒設定、空值、非空值): 
${file-my.file.txt} :假如 $file 沒有設定,則使用 my.file.txt 作傳回值。(空值及非空值時不作處理) 
${file:-my.file.txt} :假如 $file 沒有設定或為空值,則使用 my.file.txt 作傳回值。 (非空值時不作處理)
${file+my.file.txt} :假如 $file 設為空值或非空值,均使用 my.file.txt 作傳回值。(沒設定時不作處理)
${file:+my.file.txt} :若 $file 為非空值,則使用 my.file.txt 作傳回值。 (沒設定及空值時不作處理)
${file=my.file.txt} :若 $file 沒設定,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt 。 (空值及非空值時不作處理)
${file:=my.file.txt} :若 $file 沒設定或為空值,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt 。 (非空值時不作處理)
${file?my.file.txt} :若 $file 沒設定,則將 my.file.txt 輸出至 STDERR。 (空值及非空值時不作處理)
${file:?my.file.txt} :若 $file 沒設定或為空值,則將 my.file.txt 輸出至 STDERR。 (非空值時不作處理)

tips:
以上的理解在於, 你一定要分清楚 unset 與 null 及 non-null 這三種賦值狀態.
一般而言, : 與 null 有關, 若不帶 : 的話, null 不受影響, 若帶 : 則連 null 也受影響.


還有哦,${#var} 可計算出變量值的長度:
${#file} 可得到 27 ,因為 /dir1/dir2/dir3/my.file.txt 剛好是 27 個字節...

接下來,再為大家介稍一下 bash 的組數(array)處理方法。
一般而言,A="a b c def" 這樣的變量只是將 $A 替換為一個單一的字串,
但是改為 A=(a b c def) ,則是將 $A 定義為組數...
bash 的組數替換方法可參考如下方法:
  1. ${A[@]} 或 ${A[*]}
复制代码
可得到 a b c def (全部組數)
  1. ${A[0]}
复制代码
可得到 a (第一個組數),${A[1]} 則為第二個組數...
  1. ${#A[@]} 或 ${#A[*]}  
复制代码
可得到 4 (全部組數數量)
  1. ${#A[0]}
复制代码
可得到 1 (即第一個組數(a)的長度),${#A[3]} 可得到 3 (第四個組數(def)的長度)
  1. A[3]=xyz  
复制代码
則是將第四個組數重新定義為 xyz ...

諸如此類的.... 
能夠善用 bash 的 $( ) 與 ${ } 可大大提高及簡化 shell 在變量上的處理能力哦~~~  ^_^

好了,最後為大家介紹 $(( )) 的用途吧:它是用來作整數運算的。
在 bash 中,$(( )) 的整數運算符號大致有這些:
+ - * / :分別為 "加、減、乘、除"。
% :餘數運算
& | ^ !:分別為 "AND、OR、XOR、NOT" 運算。

例:
  1. $ a=5; b=7; c=2
  2. $ echo $(( a+b*c ))
  3. 19
  4. $ echo $(( (a+b)/c ))
  5. 6
  6. $ echo $(( (a*b)%c))
  7. 1
复制代码


在 $(( )) 中的變量名稱,可於其前面加 $ 符號來替換,也可以不用,如:
$(( $a + $b * $c)) 也可得到 19 的結果

此外,$(( )) 還可作不同進位(如二進位、八進位、十六進位)作運算呢,只是,輸出結果皆為十進位而已:
echo $((16#2a)) 結果為 42 (16進位轉十進位)
以一個實用的例子來看看吧:
假如當前的  umask 是 022 ,那麼新建文件的權限即為:
  1. $ umask 022
  2. $ echo "obase=8;$(( 8#666 & (8#777 ^ 8#$(umask)) ))" | bc
  3. 644
复制代码


事實上,單純用 (( )) 也可重定義變量值,或作 testing:
a=5; ((a++)) 可將 $a 重定義為 6 
a=5; ((a--)) 則為 a=4
a=5; b=7; ((a < b)) 會得到  0 (true) 的返回值。
常見的用於 (( )) 的測試符號有如下這些:
  • <:小於
    >:大於
    <=:小於或等於
    >=:大於或等於
    ==:等於
    !=:不等於
# U591387 偷懒的电梯 ## 题目背景 rtxz正在家里孜孜不倦的卷物理,不知不觉间 $24$ 个时间单位就过去了(我说是分钟你信吗),rtxz感到饥饿无比,于是他决定去楼下小卖部去买一包康帅傅红苕牛禸面配一瓶雷毙。由于rtxz做物理题有点太入迷,即使他住在一楼也要进电梯~~研究制作电梯的材料的密度~~。 ## 题目描述 rtxz所居住的这栋楼共 $m$ 层,有 $n$ 个电梯(保证每个电梯均可通往 $1$ ~ $m$ 层),编号分别为 $1$ ~ $n$ 且按从小到大的顺序严格排列。rtxz居住在第 $k$ 层,当他出家门时,这 $n$ 个电梯分别停靠在第 $a_1,a_2,a_3…a_n$ 层。这 $n$ 个电梯的速度分别为 $v_1,v_2,v_3…v_n$ (天知道为什么不一样),保证在rtxz到达楼下小卖部之前没有其他任何人按电梯或乘坐电梯且电梯运行正常。rtxz走到了编号为 $x$ 的电梯的正前方,当rtxz按下电梯按钮时,所有电梯会同时收到信息,并在 $0.2s$ 内派出来到第 $k$ 层时间最短且离rtxz最近的电梯到第 $k$ 层(因为电梯很懒,而且不想等太多rtxz走路时间),如果有多个,将会派出编号更大的一个。 现在电梯的前程序员的程序~~被人hack了~~突然出了故障,无法运行,因此物业请你以最快的速度重新写出符合要求的程序判断出该派出哪一个电梯,千万千万不要耽误rtxz吃红苕牛禸面啊! ## 输入格式 第一行 $4$ 个正整数,分别表示 $n, m, x, k$ 。 第二行 $n$ 个正整数表示 $a_1,a_2,a_3…a_n$ 。 第三行 $n$ 个正整数表示 $v_1,v_2,v_3…v_n$ 。 ## 输出格式 一行一个正整数表示应派出的电梯的编号。 ## 输入输出样例 #1 ### 输入 #1 ``` 1 1 1 1 1 1 ``` ### 输出 #1 ``` 1 ``` ## 说明/提示 ### 样例解释 我猜是人类都能看懂。 ### 数据范围 对于 $100\%$ 的数据,保证 $1 \le x \le n \le 10^4$ , $1 \le k \le m \le 10^4$ , 且对于所有满足 $1 \le i \le n$ 的正整数 $i$ , 保证 $1 \le a_i \le m$$1 \le v_i \le 10^{18}$ , $a_i$$v_i$ 均为正整数。 ### $\color{white}{提示}$ $\color{white}{不要被输入格式和数据范围坑了哦……}$ 解题,用c++写
08-03
# U230451 [USACO 05 OCT] Skiing G ## 题目背景 本题使用 `spj` ## 题目描述 $\rm Bessie$ 和农夫约翰的其他奶牛在这个冬天要去滑雪。有一天,贝西发现自己在海拔 $E(-25\le E\le25)$$R(1\le R\le100)$$C(1\le C<\le100)$ 网格的左上角。为了加入 FJ 和其他奶牛的迪斯科派对,她必须尽快到达右下角,只能向北、向南、向东、向西行驶。 $\rm Bessie$ 开始时以初始速度 $V(1 \le V \le 10^6)$ 行驶。她发现她的速度和她的海拔变化之间有一个显著的关系。当 $\rm Bessie$ 从一个高度为 $A$ 的位置移动到相邻的 $8$$B$ 的位置时,她的速度乘以数字 $2^{(A-B)}$。Bessie从一个地点到相邻地点所需的时间是她在第一个地点时速度的倒数。 请输出 $\rm Bessie$ 到她的朋友那里所需的最小时间。 ## 输入格式 第 $1$ 行,三个整数。$V,R,C$,分别代表贝西的初始速度和网格中的行数和列数。 接下来 $R$ 行,每行 $C$ 个整数,表示网格上相应位置的海拔 $E$。 ## 输出格式 输出一个整数,输出到小数点后两位:$\rm Bessie$ 到达网格右下角的最小时间量(本题使用 `spj`,要求误不超过 $10^{-2}$ 即可得分)。 ## 输入输出样例 #1 ### 输入 #1 ``` 1 3 3 1 5 3 6 3 5 2 4 3 ``` ### 输出 #1 ``` 29.00 ``` ## 说明/提示 ### 样例解释: 贝西的最佳路线是: - 从 $(1,1)$ 处开始,时间 $0$,速度 $1$。 - 东至 $(1,2)$ 时间 $1$ 速度 $\dfrac{1}{16}$。 - 南到 $(2,2)$ 时间 $17$ 速度 $\dfrac{1}{4}$ - 南至 $(3,2)$ 时间 $21$ 速度 $\dfrac{1}{8}$ - 东至 $(3,3)$ 时间 $29$ 速度 $\dfrac{1}{4}$
07-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值