使用shell讀取ini文件方法步驟

動機

我決定編寫一個腳本來進行幹凈的 macOS (BSD) / Linux 的初始設置。 我認為有一個 tsukkomi 說“現在大多數發行版都預裝瞭 perl / python”,但我決定使用 Shell 腳本(bash),因為它易於編寫進程過程。 但是,用shell語法寫各種配置文件是不可讀的,所以我決定把配置文件寫成.ini文件,用sed處理,然後加載到shell中。 關於使用 sed 解析 .ini 文件,如果你在 google 上搜索會出現各種示例,但我決定將其作為可以處理 .ini 文件(如)的規范,通過引用它們更具可讀性。

.ini 類文件格式

  • 在 [section] 中設置節。緊接在 [和緊接之前] 之後的空白字符序列(空格 / 制表符)不被視為部分名稱的一部分。 (規定可以在節名及其前後的括號之間放置空格字符。)但是,節名不應包含換行符。
  • 用 parameter = value 設置參數變量及其值。 = 前後可以有空格。假設參數名稱不包括=。如果參數名稱包含不能在 shell 變量中使用的字符,則在輸出的 shell 變量名稱中將這些字符替換為 _。
  • 如果行尾有 \,則下一行被視為續行。如果一行的開頭有 4 個或更多空格/制表符,則將其視為上一行的續行。
  • 忽略 # ,; 中的行尾作為註釋。
  • 忽略不包含 [and’]’ 的行,或在行首以外的位置不包含 = 的行。

在 shell 腳本中處理 .ini 文件時要執行的操作

查看部分列表。

將參數作為 shell 變量讀取。 然而,作為一種變體

1. 讓特定部分的參數為 shell 變量。 在某些情況下,將其設置為 shell 函數中的局部變量或環境變量。
2. 讓所有或部分部分的參數為 shell 變量。 shell變量名是’基於段名的前綴’+‘參數名’。 同樣在這種情況下,將其設置為局部變量或環境變量。 基於節名的前綴是通過將節名字符串中的shell變量中不能使用的字符替換為_並在末尾添加_來生成的。

假定處理系統

  • bash
  • BSD sed(我不能使用方便的 GNU sed 擴展,但我想在幹凈的 macOS 上運行它。)但是,我使用帶有 -E 選項的擴展正則表達式。 (因為如果不能使用一個或多個匹配元字符’+',sed 語句就會變長。)

處理連續行和註釋似乎有更普遍的用途,所以我單獨描述。 通過將代碼添加到那裡描述的 sample5.sed 來實現上述內容。

查看部分列表

這相對容易。 不要處理與節名格式不匹配的行。 您所要做的就是刪除與節名格式和輸出相對應的行中的’[‘,’]’ 和不必要的部分。 這時候需要註意的是,換行符不是隨便刪的,如單獨描述的,匹配換行符以外的表達式([^ \ [:space:]]] | [[ : 空白: ]]) 被使用。

:begin
$!N
s/[#;]([^[:space:]]|[[:blank:]])*([^\\[:space:]]|[[:blank:]])(\n)/\3/
s/[#;]([^[:space:]]|[[:blank:]])*(\\)(\n)/\2\3/
$s/[#;]([^[:space:]]|[[:blank:]])*$//
/(\\\n|\n[[:blank:]]{4})/ {
  s/[[:blank:]]*(\\\n|\n[[:blank:]]{4})[[:blank:]]*/ /
  t begin
}
/^[[:blank:]]*\n/ D
/\n[[:blank:]]*$/ {
  s/\n[[:blank:]]*$//
  t begin
}
/^\[([^[:space:]]|[[:blank:]])*\]/! D
s/\[[[:blank:]]*//
s/[[:blank:]]*\]([^[:space:]]|[[:blank:]])*//
P
D

例如,如果您嘗試將其作為示例 .ini 文件,

# -*- mode: conf-mode ; -*- \
#;
#; sample .ini file
#;
#;

[tako]
param_a=(1 # 2 3 \
4 5 ### 6 7 
    8 9 # 10
    )

a=b # kani \
# kani \


[kani]
param_a=1
param_b=2

[uni]
param_a=3
param_b=4

[wani]
param_a=5
param_b=6

[hebi]
param_a=9
param_b=10

output example:

% sed -nE -f list_section.sed sample.ini
tako
kani
uni
wani
hebi

僅提取特定部分

下面的示例僅從上面的示例中提取特定部分 (wani) 的行,這些行遵循正確的參數定義格式。如果您找到以節名形式存在的一行,請將節名存儲在保留空間中,否則如果保留空間的內容與所需的節名不匹配,則轉到下一行。…如果匹配,則檢查是否匹配參數格式的定義,去掉空格,本例中添加文本,使其成為shell函數的局部變量,可以總結shell變量定義。在行尾。因為已經變長瞭,所以加瞭註釋行,但是作為控制結構,對每個處理都進行必要的處理,如果後面的處理沒有必要,就直接回到開頭. , 應該比較容易理解。

:begin
$!N
# Erase comment strings
s/[#;]([^[:space:]]|[[:blank:]])*([^\\[:space:]]|[[:blank:]])(\n)/\3/
s/[#;]([^[:space:]]|[[:blank:]])*(\\)(\n)/\2\3/
$s/[#;]([^[:space:]]|[[:blank:]])*$//
# Concatenate continuation lines
/(\\\n|\n[[:blank:]]{4})/ {
  s/[[:blank:]]*(\\\n|\n[[:blank:]]{4})[[:blank:]]*/ /
  t begin
}
# Erase blank lines
/^[[:blank:]]*\n/ D
/\n[[:blank:]]*$/ {
  s/\n[[:blank:]]*$//
  t begin
}
# Check section headline and store section name to holdspace
/^([^[:space:]]|[[:blank:]])*\[([^[:space:]]|[[:blank:]])*\]/ {
h
x
s/^([^[:space:]]|[[:blank:]])*\[(([^[:space:]]|[[:blank:]])*)\].*$/\2/g
s/^[[:blank:]]*//g
s/[[:blank:]]$//g
x
D
}
# Skip line if current section is not interested one
x
/^wani$/! { 
  x
  D
}
x
# Print if it is proper parameter definition 
/^(([^[:space:]=]|[[:blank:]])*)=(([^[:space:]]|[[:blank:]])*)/ {
  s/^[[:blank:]]*/local /
  s/[[:blank:]]*=[[:blank:]]*/=/
  s/(([^[:space:]]|[[:blank:]])*)[[:blank:]]*(\n)/\1;\3/
  P
}
D

如何限定 shell 變量名

如關於您想要做什麼的部分中所述,您想要添加從部分名稱生成的前綴到 shell 變量,或者如果 .ini 文件中的參數名稱包含不能在 shell 變量中使用的字符串, 適當轉換。 作為一種簡單的方法,有多次調用sed並處理的方法,但是如果可以的話,我覺得用一個進程號sed就可以處理更漂亮。 這裡最大的限制是 sed 沒有一個保存空間。 在高級腳本語言中,可以將文本段劃分為多個變量,進行存儲、處理和組合。 另一方面,在 sed 的情況下,標準方法似乎是將多個文本作為堆棧保存和使用,並將保留空間作為分隔符並帶有換行符。

例如,在下面的示例中,保留空間從第一行開始。

  • 部分名稱
  • 帶格式化部分名稱的前綴
  • 模式空間第一行的備份
  • 模式空間第二行的備份
  • 根據.ini文件中的參數名格式化的Shell變量名

需要決定如何使用它,保持保持空間中的行數不變(下例中為 2 行),並在處理行轉換時適當恢復模式空間。 由於交換保持空間和模式空間的命令隻有gG和hH,類似的處理可能會重復出現,所以不可否認在1sed的過程中做起來真的很漂亮。

不管怎樣,下面是從上面的 sample.ini 文件中提取 wani 和 uni 部分並輸出添加瞭部分名稱的 shell 變量的定義語句的示例。 整體控制結構保持簡單,並且我添加瞭註釋,所以我希望你能看到重寫的地方以提取另一個部分,例如。

# Initialine the hold space: (Single empty line at the beginning)
1 { H ; x ; 
  # Change the expression for the defalut section name and/or variable prefix, here.
  s/^([^[:space:]]|[[:blank:]])*(\n)([^[:space:]]|[[:blank:]])*$/global\2global_/g
  x
}
:begin
$!N
# Erase comment strings
s/[#;]([^[:space:]]|[[:blank:]])*([^\\[:space:]]|[[:blank:]])(\n)/\3/
s/[#;]([^[:space:]]|[[:blank:]])*(\\)(\n)/\2\3/
$s/[#;]([^[:space:]]|[[:blank:]])*$//
# Concatenate continuation lines
/(\\\n|\n[[:blank:]]{4})/ {
  s/[[:blank:]]*(\\\n|\n[[:blank:]]{4})[[:blank:]]*/ / ; t begin
}
# Erase blank lines
/^[[:blank:]]*\n/ D
/\n[[:blank:]]*$/ {
  s/\n[[:blank:]]*$// ; t begin
}
# Check section headline and store section name to holdspace
/^([^[:space:]]|[[:blank:]])*\[([^[:space:]]|[[:blank:]])*\]/ {
  # Remove blackets and extra spaces at first line
  s/^([^[:space:]]|[[:blank:]])*\[(([^[:space:]]|[[:blank:]])*)\](([^[:space:]]|[[:blank:]])*)(\n)/\2\6/g
  s/^[[:blank:]]*//g; s/[[:blank:]]*(\n)/\1/g
  # Store the section name to the hold space, and format stored one for shell variable for the hold space
  h
  x
  s/(\n)([^[:space:]]|[[:blank:]])*$//
  s/([^[:alnum:]_]|$)/_/g
  x
  # Append the section name to the hold space.
  H
  # Remove unused line of the hold space and rearrange the remaining lines.
  x
  s/(([^[:space:]]|[[:blank:]])*)(\n)(([^[:space:]]|[[:blank:]])*)(\n)(([^[:space:]]|[[:blank:]])*)$/\4\3\1/
  x
  D
}
# Skip line if current section is not interested one
x
/^(wani|uni)(\n)/! { x ; D ; }
x
# Print if it is proper parameter definition 
/^(([^[:space:]=]|[[:blank:]])*)=(([^[:space:]]|[[:blank:]])*)/ {
  # Store current patern space text at the end of the hold space
  H

  # Build shell script variable name and store it at the end of the hold space
  s/(([^[:space:]=]|[[:blank:]])*)=.*$/\1/g
  s/^[[:blank:]]*//
  s/[[:blank:]]*$//
  s/[^[:alnum:]_]/_/g
  # If further rename of the variable name is necessary, put here.

  # Store variable name at the end of the hold space
  H

  # Build parameter variable value and keep it at pattern space
  # At first, Resore the current line text from hold space
  g
  # Remove unused lines.
  s/^(([^[:space:]]|[[:blank:]])*\n){2}//
  s/(\n([^[:space:]]|[[:blank:]])*){2}$//
  # Remove the text other than the parameter value
  s/^([^[:space:]=]|[[:blank:]])*=//g
  # If further formatting of the value is necessary, put here.

  # Append hold space stored date into pattern space
  G
  # Remove unused lines from the pattern space
  s/^(([^[:space:]]|[[:blank:]])*\n)(([^[:space:]]|[[:blank:]])*\n)(([^[:space:]]|[[:blank:]])*\n)(([^[:space:]]|[[:blank:]])*\n)(([^[:space:]]|[[:blank:]])*\n)/\1\5\9/
  # Rearrance the order of line in the pattern space, it is nessacery because only \1 ...\9 is avaiable
  s/^(([^[:space:]]|[[:blank:]])*\n)(([^[:space:]]|[[:blank:]])*\n)(([^[:space:]]|[[:blank:]])*)(\n)(([^[:space:]]|[[:blank:]])*)$/\1\3\8\7\5/

  # Format the output in the first line of the pattern space, and 
  # Restore the next line at the second line of the pattern space
  s/^(([^[:space:]]|[[:blank:]])*)(\n)(([^[:space:]]|[[:blank:]])*)(\n)(([^[:space:]]|[[:blank:]])*)(\n([^[:space:]]|[[:blank:]])*)$/local \4\7=\1;\9/

  # Clean up hold space
  x
  s/(\n([^[:space:]]|[[:blank:]])*){3}$//
  x
  P
}
D

output example:

% sed -n -E -f pickup_section2.sed sample.ini
local uni_param_a=3;
local uni_param_b=4;
local wani_param_a=5;
local wani_param_b=6;

Shell scripting

每次更改要提取的section或者切換輸出格式(sh/csh、shell變量/局部變量/環境變量、變量名前綴的ON/OFF)都要重寫sed文件很麻煩,所以命令行我準備瞭生成 sed 命令作為選項的 shell 腳本。 使用另一篇文章中的模板生成。 對於上面的seds,我還嘗試瞭通過.ini文件的參數變量名(shell變量名)來選擇輸出。 (但是,如果指定瞭多個段名和變量名,組合不是唯一的,所以它可能不是一個很有用的功能。)

文件存儲:

https://github.com/nanigashi-uji/parse_ini_sh
https://gitlab.com/nanigashi_uji/parse_ini_sh

如何使用

[Usage] % parse_ini.sh -list     file [files ...]
        % parse_ini.sh [options] file [files ...]

[Options]
    -l,--list                       : List sections 
    -S,--sec-select       name      : Section name to select
    -T,--sec-select-regex expr      : Section reg. expr. to select
    -V,--variable-select name       : variable name to select
    -W,--variable-select-regex expr : variable reg. expr. to select
    -L,--local                      : Definition as local variables (B-sh)
    -e,--env                        : Definition as enviromnental variables
    -q,--quot                       : Definition by quoting with double/single-quotation.
    -c,--csh,--tcsh                 : Output for csh statement (default: B-sh)
    -b,--bsh,--bash                 : Output for csh statement (default)
    -s,--sec-prefix                 : add prefix: 'sectionname_' to variable names. 
    -v,--verbose                    : Verbose messages 
    -h,--help                       : Show Help (this message)

output example:

% parse_ini.sh –list sample.ini
tako
kani
uni
wani
hebi

% parse_ini.sh -S kani -L sample.ini
local param_a=1;
local param_b=2;

% parse_ini.sh -S kani -L -s sample.ini
local kani_param_a=1;
local kani_param_b=2;

% parse_ini.sh -S kani -L -e -c sample.ini
setenv param_a 1;
setenv param_b 2;

% parse_ini.sh -S kani -L -e -c -q sample.ini
setenv param_a "1";
setenv param_b "2";

 到此這篇關於使用shell讀取ini文件方法步驟的文章就介紹到這瞭,更多相關shell讀取ini文件內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: