一行bash编程技巧

1. 清空文件内容

$ > file

这一行命令用到了输出重定向操作符>。输出重定向发生时,文件会被打开准备写入。如果此时文件不存在则先创建,存在则将其大小截取为0。这里我们并没有重定向写任何内容到文件中,所以文件依然保持为空。

如果你想替换文件的内容,或者创建一个包含指定内容的文件,可以运行下面的命令:

$ echo "some string" > file

2. 追加内容到文件

$ echo "foo bar baz" >> file

这一行命令用到了另外一个输出重定向操作符>>,该操作符将内容追加到文件。同样地,如果文件不存在则先创建它。追加的内容之后,紧跟着换行符。如果你不想要追加换行符,在执行echo命令时可以指定-n选项:

$ echo -n "foo bar baz" >> file

3. 读取文件的首行并赋值给变量

$ read -r line < file

这一行命令用到了 Bash 的内置命令read,和输入重定向操作符<。read命令从标准输入中读取一行,并将内容保存到变量line中。在这里,-r选项保证读入的内容是原始的内容,意味着反斜杠转义的行为不会发生。输入重定向操作符< file打开并读取文件file,然后将它作为read命令的标准输入。

记住,read命令会删除包含在IFS变量中出现的所有字符,IFS 的全称是 Internal Field Separator,Bash 根据 IFS 中定义的字符来分隔单词。在这里,read命令读入的行被分隔成多个单词。默认情况下,IFS包含空格,制表符和回车,这意味着开头和结尾的空格和制表符都会被删除。如果你想保留这些符号,可以通过设置IFS为空来完成:

$ IFS= read -r line < file

IFS 的变化仅会影响当前的命令,这行命令可以保证读入原始的首行内容到变量line中,同时行首与行尾的空白字符被保留。

另外一种读取文件首行内容,并赋值给变量的方法是:

$ line=$(head -1 file)

这里用到了命令替换操作符$(...),它运行括号里的命令并且将输出返回。 这个例子中,命令是head -1 file,输出的内容是文件的首行。输入然后通过等号赋值给变量line。$(...)的等价写法是`...`,所以也可以换成下面这样:

$ line=`head -1 file`

不过,在 Bash 中$(...)用法更加推荐,因为它看起来更加整洁,并且容易嵌套使用。

4. 依次读入文件每一行

$ while read -r line; do

    # do something with $line

done < file

这是一种正确的读取文件内容的做法,read命令放在while循环中。当read命令遇到文件结尾时(EOF),它会返回一个正值,导致循环判断失败终止。

记住,read命令会删除首尾多余的空白字符,所以如果你想保留,请设置 IFS 为空值:

$ while IFS= read -r line; do

    # do something with $line

done < file

如果你不想将< file放在最后,可以通过管道将文件的内容输入到 while 循环中:

$ cat file | while IFS= read -r line; do

    # do something with $line

done

5. 随机读取一行并赋值给变量

$ read -r random_line < <(shuf file)

Bash 中并没有提供一种直接的方法来随机读取文件的某一行内容,所以这里需要利用外部程序。在最新的一些 Linux 系统上,GNU Coreutils 包中提供的shuf命令可以满足我们的需求。

这一行命令中用到了进程替换(process substitution)操作符<(...)。进程替换操作会创建一个匿名的管道文件,并将进程命令的标准输出连接到管道的写一端。然后 Bash 开始执行进程替换中的命令,然后将整个进程替换的表达式替换成匿名管道的文件名。

当 Bash 看到<(shuf file)时,它首先打开一个特殊的文件/dev/fd/n,这里的n是一个空闲的文件描述符,然后执行shuf file命令,将标准输出连接到/dev/fd/n,并且替换<(shuf file)为/dev/fd/n,因此实际的命令会变成:

$ read -r random_line < /dev/fd/n

结果会读取洗牌后的文件的第一行内容。

另外一种做法是,使用 GNU sort 命令,它提供的-R选项可以随机排序文件:

$ read -r random_line < <(sort -R file)

或者,同前面一样,将结果赋值给变量:

$ random_line=$(sort -R file | head -1)

这里,我们首先通过sort -R随机排序文件,然后通过head -1读取文件的第一行。

6. 读取文件首行前三个字段并赋值给变量

$ while read -r field1 field2 field3 throwaway; do

    # do something with $field1, $field2, and $field3

done < file

如果在read命令中指定多个变量名,它会将读入的内容分隔成多个字段,然后依次赋值给对应的变量,第一个字段赋值给第一个变量,第二个字段赋值给第二个变量,等等,最后将剩余的所有字段赋值给最后一个变量。这也是为什么,在上面的例子中,我们加了一个throwaway变量,否则的话,当文件的一行大于三个字段时,第三个变量的内容会包含所有剩余的字段。

有时候,为了书写方便,可以简单地用_来替换throwaway变量:

$ while read -r field1 field2 field3 _; do

    # do something with $field1, $field2, and $field3

done < file

又或者,如果你的文件确实只有三个字段,那可以忽略它:

$ while read -r field1 field2 field3; do

    # do something with $field1, $field2, and $field3

done < file

下面是一个例子,假如你想知道一个文件到底包含多少行,多少个单词以及多少个字节。当你执行wc命令时,你会得到3个数字加上文件名,文件名在最后:

$ cat file-with-5-lines

x 1

x 2

x 3

x 4

x 5

$ wc file-with-5-lines

5 10 20 file-with-5-lines

所以,这个文件包含5行,10个单词,以及20个字符。我们接下来,可以通过read命令将这些信息保存到变量中:

$ read lines words chars _ < <(wc file-with-5-lines)

$ echo $lines

5

$ echo $words

10

$ echo $chars

20

类似地,你也可以使用here-strings将字符串分隔并保存到变量中。假设你有一个字符串变量$info,内容为"20 packets in 10 seconds",然后你想要将从中获取20和10。在不久之前,我是这样来完成的:

$ packets=$(echo $info | awk '{ print $1 }')

$ time=$(echo $info | awk '{ print $4 }')

然而,得益于read命令的强大和对 Bash 的了解,我们可以这样做:

$ read packets _ _ time _ <<< "$info"

这里,<<<就是 here-string 的语法,它允许你直接传递字符串给标准输入。

7. 保存文件的大小到变量

$ size=$(wc -c < file)

这一行命令中用到了第3点中介绍的命令替换操作$(...),它运行里面的命令并将结果获取回来。在这个例子中,命令是wc -c < file,它输出文件的字节数。这个结果最终会赋值给变量size。

8. 从文件路径中获取文件名

假设,你有一个文件,它的路径为/path/to/file.ext,然后你要从中获取文件名,在这里是file.ext。你要怎么做? 一个好的方法是通过参数展开(parameter expansion)功能:

$ filename=${path##*/}

这一行命令使用了参数展开的语法:${var##pattern},它从$var字符串开始处开始匹配pattern。如果能够匹配成功,将最长匹配的内容删除后再返回。

在这个例子中,匹配的模式是*/,它尝试匹配/path/to/file.ext的开始部分,正如前面所说,这里是贪婪匹配,所以它能够匹配到最后一个斜杠为止,即匹配的内容是/path/to/。所以当把匹配的内容删除后,返回的内容就是文件名file.ext。

9. 从文件路径中获取目录名

和上面一样类似,这次你要从路径/path/to/file.txt中获取目录名/path/to。你可以继续通过参数展开功能来完成这个任务:

$ dirname=${path%/*}

这次的用法是${var%pattern},它从$var的结尾处匹配/*。如果能够成功匹配,将最短匹配的内容删除再返回。

在这个例子中,匹配的模式是/*,它能够匹配/file.ext部分,删除这部分内容后返回的就是目录名称。

10. 快速拷贝文件

假设你要将文件/path/to/fil拷贝到/path/to/file_copy,一般情况下,大多数人会这么来写:

$ cp /path/to/file /path/to/file_copy

不过,你可以利用括号展开(brace expansion){...}功能:

$ cp /path/to/file {,_copy}

括号展开可以生成任意字符串的组合,在这个例子中,/path/to/file{,_copy}最终生成/path/to/file /path/to/file_copy。所以上面这行命令最终发型成:

$ cp /path/to/file /path/to/file_copy

类似地,你可以执行下面的命令快速的移动文件:

$ mv /path/to/file{,_old}

这行命令展开后就变成了:

$ mv /path/to/file /path/to/file_old

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容

  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,380评论 0 5
  • 1.创建文件夹 !/bin/sh mkdir -m 777 "%%1" 2.创建文件 !/bin/sh touch...
    BigJeffWang阅读 10,035评论 3 53
  • .bat脚本基本命令语法 目录 批处理的常见命令(未列举的命令还比较多,请查阅帮助信息) 1、REM 和 :: 2...
    庆庆庆庆庆阅读 8,076评论 1 19
  • 文/黄梅枝 王娟看到爸爸的样子很伤心,王慧气得在病房里搓手打转转,王慧略带责怪王娟的口气说:“娟子你也忒没有脾气了...
    黄梅枝阅读 959评论 23 24
  • 年初五清晨,我们被围观。 医院门前,我和妈妈下车。 你们从哪里来? 指挥停车的老头儿,头发斑白,好似看到原始人一样...
    兰露儿阅读 545评论 13 15