Sau một hồi nghịch ngợm tìm hiểu về bash script hôm nay mình có tổng hợp lại một số hàm có thể hay gặp khi sử dụng bash script. MÌnh xin phép được bỏ qua một số những định nghĩa cơ bản và tập trung nhiều hơn vào việc thực hành
Khai báo biến trong bash script
Khai báo biến local
Chắc hẳn chúng ta đều đã quen thuộc với cách khai báo một biến trong bash như sau
1 2 3 4 5 6 7 8 9 10 11 | var<span class="token operator">=</span><span class="token string">"test"</span> demo_variable<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> var2<span class="token operator">=</span><span class="token string">"test variable"</span> <span class="token keyword">echo</span> <span class="token variable">$var</span> <span class="token keyword">echo</span> <span class="token variable">$var2</span> <span class="token punctuation">}</span> demo_variable <span class="token keyword">echo</span> <span class="token variable">$var</span> <span class="token keyword">echo</span> <span class="token variable">$var2</span> |
Kết quả:
1 2 3 4 5 | test test variable test test variable |
Biến này sẽ được sử dụng xuyên suốt trong script. Dù ở trong function vẫn có thể sử dụng được hoặc khai báo trong function và ở ngoài vẫn có thể dụng được.
Tuy nhiên trong 1 số trường hợp nếu muốn giới hạn lại phạm vi sử dụng của biến chỉ trong functions thôi chúng ta có thể sử dụng biến local như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 | try_local_variable<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> local var<span class="token operator">=</span><span class="token string">"Test local variable"</span> <span class="token keyword">echo</span> <span class="token variable">$var</span> <span class="token punctuation">}</span> try_local_variable <span class="token keyword">if</span> <span class="token punctuation">[</span> -n <span class="token string">"<span class="token variable">$var</span>"</span> <span class="token punctuation">]</span> <span class="token keyword">then</span> <span class="token keyword">echo</span> <span class="token variable">$var</span> <span class="token keyword">else</span> <span class="token keyword">echo</span> <span class="token string">"Parameter not supplied"</span> <span class="token keyword">fi</span> |
Kết quả:
1 2 3 | Test local variable Parameter not supplied |
Lấy giá trị của biến từ string
1 2 3 4 5 | var<span class="token operator">=</span><span class="token string">"test"</span> var2<span class="token operator">=</span><span class="token string">"var"</span> <span class="token keyword">echo</span> <span class="token string">"<span class="token variable">${!var2}</span>"</span> |
Kết quả
1 2 | test |
Ngoài ra có thể thực hiện gán giá trị vào một biến khác như sau
1 2 3 4 5 6 | var<span class="token operator">=</span><span class="token string">"test"</span> var2<span class="token operator">=</span><span class="token string">"var"</span> var3<span class="token operator">=</span><span class="token string">"<span class="token variable">${!var2}</span>"</span> <span class="token keyword">echo</span> <span class="token variable">$var3</span> |
Kết quả
1 2 | test |
Một số hàm hay sử dụng với String
Thay thế string
1 2 3 4 5 6 7 8 9 10 | var<span class="token operator">=</span><span class="token string">"test"</span> <span class="token comment"># replace first 't' only</span> bar<span class="token operator">=</span><span class="token variable">${var/t/h}</span> <span class="token keyword">echo</span> <span class="token variable">$bar</span> <span class="token comment"># replace all 't'</span> bar<span class="token operator">=</span><span class="token variable">${var//t/h}</span> <span class="token keyword">echo</span> <span class="token variable">$bar</span> |
Kết quả
1 2 3 | hest hesh |
Cut string
1 2 3 4 | var<span class="token operator">=</span><span class="token string">"this is a test"</span> <span class="token keyword">echo</span> <span class="token string">"<span class="token variable">$var</span>"</span> <span class="token operator">|</span> <span class="token function">cut</span> -d<span class="token string">' '</span> -f 4 <span class="token keyword">echo</span> <span class="token string">"<span class="token variable">$var</span>"</span> <span class="token operator">|</span> <span class="token function">cut</span> --delimiter<span class="token operator">=</span><span class="token string">' '</span> --fields<span class="token operator">=</span>4 |
Kết quả
1 2 | test |
Sử dụng array trong bash script
Duyệt qua tất cả các phần tử của mảng
1 2 3 4 5 6 | array1<span class="token operator">=</span><span class="token punctuation">(</span>1 2 3<span class="token punctuation">)</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${array1[@]}</span>"</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$element</span> <span class="token keyword">done</span> |
Kết quả
1 2 3 4 | 1 2 3 |
Merge 2 mảng
1 2 3 4 5 6 7 8 | array1<span class="token operator">=</span><span class="token punctuation">(</span>1 2 3<span class="token punctuation">)</span> array2<span class="token operator">=</span><span class="token punctuation">(</span>4 5 6<span class="token punctuation">)</span> new_array<span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">"<span class="token variable">${array1[@]}</span>"</span> <span class="token string">"<span class="token variable">${array2[@]}</span>"</span><span class="token punctuation">)</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${new_array[@]}</span>"</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$element</span> <span class="token keyword">done</span> |
Kết quả
1 2 3 4 5 6 7 | 1 2 3 4 5 6 |
Thêm phần tử vào mảng
Thêm phần tử vào đầu của mảng
1 2 3 4 5 6 7 | array<span class="token operator">=</span><span class="token punctuation">(</span>2 3 4<span class="token punctuation">)</span> array<span class="token operator">=</span><span class="token punctuation">(</span>1 <span class="token string">"<span class="token variable">${array[@]}</span>"</span><span class="token punctuation">)</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${array[@]}</span>"</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$element</span> <span class="token keyword">done</span> |
Kết quả
1 2 3 4 5 | 1 2 3 4 |
Thêm phần tử vào cuối của mảng
1 2 3 4 5 6 7 8 9 10 11 12 13 | new_array<span class="token operator">=</span><span class="token punctuation">(</span>0<span class="token punctuation">)</span> new_array<span class="token operator">=</span><span class="token punctuation">(</span> <span class="token string">"<span class="token variable">${new_array[@]}</span>"</span> 1 <span class="token punctuation">)</span> <span class="token comment"># Cách 1</span> array<span class="token operator">=</span><span class="token punctuation">(</span>2 3 4<span class="token punctuation">)</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${array[@]}</span>"</span> <span class="token keyword">do</span> new_array+<span class="token operator">=</span><span class="token punctuation">(</span><span class="token variable">$element</span><span class="token punctuation">)</span> <span class="token comment"># Cách 2</span> <span class="token keyword">done</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${new_array[@]}</span>"</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$element</span> <span class="token keyword">done</span> |
Kết quả
1 2 3 4 5 6 | 0 1 2 3 4 |
Thêm phần tử vào vị trí xác định của mảng
Để làm việc này cần phải làm theo 3 bước như sau
- Lấy tất cả các element trước vị trí index “x”
- Thêm một element vào mảngAdd an element to the array
- Lấy tất cả các element từ vị trí index “x” trở về sau,
Ví dụ như format bên dưới: Thêm element 4 vào vị trị index = 2 của mảng
1 2 3 4 5 6 7 | array<span class="token operator">=</span><span class="token punctuation">(</span>0 1 3 5<span class="token punctuation">)</span> array<span class="token operator">=</span><span class="token punctuation">(</span> <span class="token string">"<span class="token variable">${array[@]:0:2}</span>"</span> 4 <span class="token string">"<span class="token variable">${array[@]:2}</span>"</span> <span class="token punctuation">)</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${array[@]}</span>"</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$element</span> <span class="token keyword">done</span> |
Kết quả
1 2 3 4 5 6 | 0 1 4 3 5 |
Xóa phần tử ra khỏi mảng
Chúng ta sẽ cần thực hiện 2 bước sau
- Lấy tất cả các element trước vị trí index “x”
- Lấy tất cả các element từ vị trí index “x” + “n” trở về sau
Ví dụ như format bên dưới: Xóa element khỏi vị trí index = 2 của mảng
1 2 3 4 5 6 7 | array<span class="token operator">=</span><span class="token punctuation">(</span>0 1 3 5<span class="token punctuation">)</span> array<span class="token operator">=</span><span class="token punctuation">(</span> <span class="token string">"<span class="token variable">${array[@]:0:2}</span>"</span> <span class="token string">"<span class="token variable">${array[@]:3}</span>"</span> <span class="token punctuation">)</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${array[@]}</span>"</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$element</span> <span class="token keyword">done</span> |
Kết quả
1 2 3 4 | 0 1 5 |
Ngoài ra có thể sử dụng cách khác khi sử dụng hàm unset
như sau
1 2 3 4 5 6 7 | array<span class="token operator">=</span><span class="token punctuation">(</span>0 1 3 5<span class="token punctuation">)</span> unset -v <span class="token string">'array[1]'</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${array[@]}</span>"</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$element</span> <span class="token keyword">done</span> |
Kết quả
1 2 3 4 | 0 3 5 |
Một cách khác khi bạn biết chính xác được giá trị của element trong mảng bạn có thể sử dụng cách thay thế tương tự như việc thay thế string theo format.
1 2 | array<span class="token operator">=</span><span class="token punctuation">(</span> <span class="token string">"<span class="token variable">${array[@]/PATTERN/}</span>"</span> <span class="token punctuation">)</span> |
Ở đây chỉ cần sử dụng 1 dấu /
là đủ thay thế tất cả các giá trị map
1 2 3 4 5 6 7 | array<span class="token operator">=</span><span class="token punctuation">(</span>0 1 3 5 1 2<span class="token punctuation">)</span> array<span class="token operator">=</span><span class="token punctuation">(</span> <span class="token string">"<span class="token variable">${array[@]/1/}</span>"</span> <span class="token punctuation">)</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${array[@]}</span>"</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$element</span> <span class="token keyword">done</span> |
Kết quả
1 2 3 4 5 6 7 | 1 3 5 2 |
Làm việc với file
Giả sử chúng ta có một file tên text.txt với nội dung như sau:
1 2 3 | Line number 1 Line number 2 |
Đọc tất cả các dòng trong một file
1 2 3 4 5 | <span class="token keyword">while</span> IFS<span class="token operator">=</span><span class="token string">""</span> <span class="token function">read</span> -r line <span class="token operator">||</span> <span class="token punctuation">[</span> -n <span class="token string">"<span class="token variable">$line</span>"</span> <span class="token punctuation">]</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$line</span> <span class="token keyword">done</span> <span class="token operator"><</span> text.txt |
Kết quả
1 2 3 | Line number 1 Line number 2 |
Chỉnh sửa file
Thêm vào đầu file
1 2 3 4 | filename<span class="token operator">=</span><span class="token string">"text.txt (echo "</span>New line added<span class="token string">" | cat - <span class="token variable">$filename</span>) > "</span><span class="token variable">$filename</span><span class="token string">".tmp && mv "</span><span class="token variable">$filename</span><span class="token string">".tmp "</span><span class="token variable">$filename</span>" <span class="token function">cat</span> <span class="token variable">$filename</span> |
Kết quả
1 2 3 4 | New line added Line number 1 Line number 2 |
Với cách này chúng ta sẽ thực hiện bằng cách tạo ra file với đuôi .tmp sau đó thực hiện lệnh mv
để tổi file tmp thành tên file ban đầu
Thêm vào một line bất kỳ của file
Chúng ta có thể sử dụng bằng lệnh sed
với format <line>i<PATTERN>
.
Ví dụ dưới đây chúng ta sẽ thêm vào dòng số 1 của file với nội dung là “Line number 0”. Lưu ý ở đây rằng <line>
phải nhỏ hơn hoặc bằng số dòng trong file
1 2 3 4 | filename<span class="token operator">=</span><span class="token string">"text.txt sed -i "</span>1iLine number 0" <span class="token variable">$filename</span> <span class="token function">cat</span> <span class="token variable">$filename</span> |
Kết quả
1 2 3 4 | Line number 0 Line number 1 Line number 2 |
Thêm vào cuối file
1 2 3 4 | filename<span class="token operator">=</span><span class="token string">"text.txt echo "</span>Line number 3" <span class="token operator">>></span> <span class="token variable">$filename</span> <span class="token function">cat</span> <span class="token variable">$filename</span> |
Kết quả
1 2 3 4 | Line number 1 Line number 2 Line number 3 |
Lưu ý ở đây nếu chúng ta chỉ sử dụng 1 dấu >
thì điều có nghĩa là sẽ tạo ra file mới ví dụ như sau
1 2 3 4 | filename<span class="token operator">=</span><span class="token string">"text.txt echo "</span>Line number 3" <span class="token operator">></span> <span class="token variable">$filename</span> <span class="token function">cat</span> <span class="token variable">$filename</span> |
Kết quả
1 2 | Line number 3 |
Thay thế một text gặp trong file
Chúng ta sẽ tiếp tục sử dụng với lệnh sed
với format như sau
1 2 | <span class="token function">sed</span> -i <span class="token string">"s/PATTERN/REPLACE_PATTERN/"</span> filename |
Ví dụ chúng ta sẽ thực hiện thay thế từ “Line” thành “This is line”
1 2 3 4 | filename<span class="token operator">=</span><span class="token string">"text.txt sed -i "</span>s/Line/This is line/" <span class="token variable">$filename</span> <span class="token function">cat</span> <span class="token variable">$filename</span> |
Kết quả
1 2 3 | This is line number 1 This is line number 2 |
Đọc file yaml từ bash script
Sau một hồi tìm hiểu thì may mắn tìm được một link github viết về hàm khá đẩy đủ để đọc được file yaml với nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | <span class="token comment">#!/usr/bin/env bash</span> <span class="token comment"># shellcheck disable=SC1003</span> <span class="token comment"># Based on https://gist.github.com/pkuczynski/8665367</span> parse_yaml<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> local yaml_file<span class="token operator">=</span><span class="token variable">$1</span> local prefix<span class="token operator">=</span><span class="token variable">$2</span> local s local w local fs s<span class="token operator">=</span><span class="token string">'[[:space:]]*'</span> w<span class="token operator">=</span><span class="token string">'[a-zA-Z0-9_.-]*'</span> fs<span class="token operator">=</span><span class="token string">"<span class="token variable"><span class="token variable">$(</span><span class="token keyword">echo</span> @<span class="token operator">|</span><span class="token function">tr</span> @ <span class="token string">'34'</span><span class="token variable">)</span></span>"</span> <span class="token punctuation">(</span> <span class="token function">sed</span> -e <span class="token string">'/- [^“]'</span><span class="token string">"[^']"</span><span class="token string">'.*: /s|([ ]*)- ([[:space:]]*)|1-'$'</span>n<span class="token string">''</span> 12<span class="token operator">|</span>g<span class="token string">' | sed -ne '</span>/^--/s<span class="token operator">|</span>--<span class="token operator">||</span>g<span class="token punctuation">;</span> s<span class="token operator">|</span><span class="token string">"|\"|g; s/[[:space:]]*$//g;' -e "</span>/<span class="token comment">#.*["']/!s| #.*||g; /^#/s|#.*||g;" </span> -e <span class="token string">"s|^(<span class="token variable">$s</span>)(<span class="token variable">$w</span>)<span class="token variable">$s</span>:<span class="token variable">$s</span>"(.*)"<span class="token variable">$s</span>$|1<span class="token variable">$fs</span>2<span class="token variable">$fs</span>3|p"</span> -e <span class="token string">"s|^(<span class="token variable">$s</span>)(<span class="token variable">$w</span>)<span class="token variable">${s}</span>[:-]<span class="token variable">$s</span>(.*)<span class="token variable">$s</span>$|1<span class="token variable">$fs</span>2<span class="token variable">$fs</span>3|p"</span> <span class="token operator">|</span> <span class="token function">awk</span> -F<span class="token string">"<span class="token variable">$fs</span>"</span> <span class="token string">'{ indent = length(<span class="token variable">$1</span>)/2; if (length(<span class="token variable">$2</span>) == 0) { conj[indent]="+";} else {conj[indent]="";} vname[indent] = <span class="token variable">$2</span>; for (i in vname) {if (i > indent) {delete vname[i]}} if (length(<span class="token variable">$3</span>) > 0) { vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")} printf("%s%s%s%s=("%s")n", "'</span><span class="token string">"<span class="token variable">$prefix</span>"</span><span class="token string">'",vn, <span class="token variable">$2</span>, conj[indent-1],<span class="token variable">$3</span>); } }'</span> <span class="token operator">|</span> <span class="token function">sed</span> -e <span class="token string">'s/_=/+=/g'</span> <span class="token operator">|</span> <span class="token function">awk</span> <span class="token string">'BEGIN { FS="="; OFS="=" } /(-|.).*=/ { gsub("-|\.", "_", <span class="token variable">$1</span>) } { print }'</span> <span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token string">"<span class="token variable">$yaml_file</span>"</span> <span class="token punctuation">}</span> create_variables<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> local yaml_file<span class="token operator">=</span><span class="token string">"<span class="token variable">$1</span>"</span> local prefix<span class="token operator">=</span><span class="token string">"<span class="token variable">$2</span>"</span> <span class="token function">eval</span> <span class="token string">"<span class="token variable"><span class="token variable">$(</span>parse_yaml <span class="token string">"<span class="token variable">$yaml_file</span>"</span> <span class="token string">"<span class="token variable">$prefix</span>"</span><span class="token variable">)</span></span>"</span> <span class="token punctuation">}</span> |
Hàm parse_yaml
cần 2 giá trị input là tên file và giá trị prefix. Hàm create_variables
là để khai báo các biến sau khi đã parse các key trong file ra. Như ở ví dụ dưới đây chúng ta có file database.yml và prefix là config_
1 2 3 4 5 6 7 8 9 10 11 12 | default: adapter: mysql2 reconnect: true encoding: utf8mb4 pool: 5 host: local username: root password: 123456 port: - 3306 - 33306 |
Chúng ta sẽ thực hiện lệnh sau
1 2 3 4 5 6 7 8 | create_variables database.yml <span class="token string">"config_"</span> <span class="token keyword">echo</span> <span class="token variable">$config_default_adapter</span> <span class="token comment"># Được tạo thành từ giá trị prefix, key :default và key key :adapter</span> <span class="token keyword">for</span> element <span class="token keyword">in</span> <span class="token string">"<span class="token variable">${config_default_port[@]}</span>"</span> <span class="token keyword">do</span> <span class="token keyword">echo</span> <span class="token variable">$element</span> <span class="token keyword">done</span> |
Kết quả
1 2 3 4 | mysql2 3306 33306 |
Các bạn có thể sử dụng file mẫu để thử các case các.
Trên đây là một số hàm mình mới tìm hiểu được. Cảm ơn các bạn đã theo dõi.