0%

Bash One-Liners Explained, Part I: Working with files Note

在網路上看到這篇,做一下自己的筆記

替代,新增指定內容的字串到文件

1
$ echo "Line 1" > file

新增字串到檔案最尾端

1
$ echo "Line 2" >> file

清空檔案內容

將檔案內容全部清空,檔案大小歸零,以下兩種作法效果是一樣的。不過第二種比較容易看懂。

1
2
$ > file
$ cat /dev/null > file

讀取一行資料

可以用以下方式讀取出來

1
$ read -r line < file

這個方式會將頭尾的空白去掉,且保留字串中的反斜線(-r)。
如果要設定IFS的話,可以順便切割赤串。

1
2
$ cat "1, 2, 3" > file
$ IFS=', ' read -r first second third < file

Read前面的IFS只影響當前的read指令,執行完之後恢復原狀。
原作中所說的

1
2
3
4
$ echo "              Emptry                        End" > file
$ IFS= read -r line < file
$ echo ${line}
Emptry End

保留空白一點效果都沒有,只好寫成這個樣子

1
2
3
4
5
6
$ SAVEIFS=$IFS
$ IFS=
$ read -r line < ttt
$ echo ${line}
Emptry End
$ IFS=$SAVEIFS

另外也可以用這種寫法

1
2
$ line=${head -1 file}
$ line=`head -1 file`

也可以這樣寫

1
2
$ IFS= line=${head -1 file}
$ IFS= line=`head -1 file`

這邊的IFS就正常了,應該是Bash的Bug吧@@。

讀取文件的每一行

1
2
3
$ while IFS= read -r line; do
# do something with ${line}}
done < file

另一種寫法,利用pipe來做

1
2
3
$ cat file | while IFS= read -r line; do
# do something with ${line}}
done

隨機讀取檔案的任合一行

同樣的,達成這樣功能也是有很多作法,例如使用Process substitution建立一個匿名pipi。

1
2
$ read -r random_line < <(shuf file)
$ read -r random_line < <(sort -R file)

上面的shuf是用來此亂檔案中美一行的排列順序,而取打亂檔案的第一行。不然可以用sort -R代替。
同樣的也可以使用Pipe來達成工作。

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

讀取前三個字串

假設目前檔案內容是aaa bbb ccc ddd eee。我們可以用

1
$ read -r var1 var2 var3 throwaway < file

如果不在var3後面加個變數的話,var3的內容救變成ccc ddd eee了。
如果你根本不關心throwaway內容的話,可以寫成

1
$ read -r var1 var2 var3 _ < file

如果檔案內容是aaa bbb的話,var3的內容就是空的。

讀取一個文件檔有幾行,幾個單字,字元數目

同樣的,以上面aaa bbb ccc ddd eee為範例。基本上就是上面的技巧,加上wc的輸出結果。wc的用法google一下即可。

1
$ read -r lines words chars _ < <(wc abcd)

直接從字串中讀取資料

假設我們現在有個字串$info叫做`20 packets in 10 seconds”,如何取出packets跟time。
使用awk的作法會是

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

透過Here strings跟read指令可以寫的更輕鬆

1
$ read packets _ _ time _ <<< $info

獲得檔案的大小

一樣是wc的用法,只不過現在只需要char count。

1
$ size=$(wc -c < file)

從文件路徑獲得文件名稱根目錄資訊

看起來很襖,不過實際上使用有其侷限。假設我們現在的路徑名稱是/path/to/file.ext,接著我們可以透過parameter expansion來擷取。

1
2
$ dirname=${path%/*}
$ filename=${path##*/}

不過檔案路徑改成非path開頭的,filename的定義也要跟著修改。

快速拷貝/搬移文件

透過Brace expansion,可以方便我們做這件事。

1
2
$ cp /path/to/file{, _copy}  // cp path/to/file path/to/file_copy
$ mv ~/work{, _backup}