2012-11-20 36 views
20

我想知道以下內容;將Bash數組轉換爲分隔字符串

  1. 爲什麼給定的非工作示例不起作用。
  2. 如果除了工作示例中給出的其他更清潔的方法。

非工作示例

> ids=(1 2 3 4);echo ${ids[*]// /|} 
1 2 3 4 
> ids=(1 2 3 4);echo ${${ids[*]}// /|} 
-bash: ${${ids[*]}// /|}: bad substitution 
> ids=(1 2 3 4);echo ${"${ids[*]}"// /|} 
-bash: ${"${ids[*]}"// /|}: bad substitution 

工作實施例

> ids=(1 2 3 4);id="${ids[@]}";echo ${id// /|} 
1|2|3|4 
> ids=(1 2 3 4); lst=$(IFS='|'; echo "${ids[*]}"); echo $lst 
1|2|3|4 

在上下文中,在用於進一步解析一個sed命令中使用的分隔的字符串。

+1

'$ {$ {IDS [*]} ///|}'是一個語法錯誤,這是所有。不知道你想在這裏實現什麼。 –

+0

試圖在1跳中實現變量替換,它永遠不會工作... – koola

回答

23
# REVISION: 2017-03-14 
# Use of read and other bash specific features (bashisms) 

因爲括號用於分隔一個陣列,而不是一個字符串:

ids="1 2 3 4";echo ${ids// /|} 
1|2|3|4 

一些樣品:用兩個字符串填充$idsa bc d

ids=("a b" "c d") 

echo ${ids[*]// /|} 
a|b c|d 

IFS='|';echo "${ids[*]}";IFS=$' \t\n' 
a b|c d 

...最後:

IFS='|';echo "${ids[*]// /|}";IFS=$' \t\n' 
a|b|c|d 

當陣列被組裝時,通過的$IFS第一炭分離,但隨着空間在陣列的每個元件所取代|

當你這樣做:

id="${ids[@]}" 

你傳遞字符串從陣列ids的合併建立一個空間字符串類型的新變量。

注:"${ids[@]}"給予空間分隔串,"${ids[*]}"(帶星*代替at符號@)將呈現由$IFS第一個字符分隔的字符串。

什麼man bash說:

man -Len -Pcol\ -b bash | sed -ne '/^ *IFS /{N;N;p;q}' 
    IFS The Internal Field Separator that is used for word splitting 
      after expansion and to split lines into words with the read 
      builtin command. The default value is ``<space><tab><newline>''. 

$IFS播放:

set | grep ^IFS= 
IFS=$' \t\n' 

declare -p IFS 
declare -- IFS=" 
" 
printf "%q\n" "$IFS" 
$' \t\n' 

字面意思是spacetabulation(意思是或) a line-feed。所以,第一個角色是空間。使用*將和@一樣。

{ 

# OIFS="$IFS" 
    # IFS=$': \t\n' 
    # unset array 
    # declare -a array=($(echo root:x:0:0:root:/root:/bin/bash)) 

IFS=: read -a array < <(echo root:x:0:0:root:/root:/bin/bash) 

    echo 1 "${array[@]}" 
    echo 2 "${array[*]}" 
    OIFS="$IFS" IFS=: 
    echo 3 "${array[@]}" 
    echo 4 "${array[*]}" 
    IFS="$OIFS" 
} 
1 root x 0 0 root /root /bin/bash 
2 root x 0 0 root /root /bin/bash 
3 root x 0 0 root /root /bin/bash 
4 root:x:0:0:root:/root:/bin/bash 

注:IFS=: read -a array < <(...)將使用:作爲分隔符,永久不設置$IFS。這是因爲輸出行#2將空格顯示爲分隔符。

+0

因此,它是一個typeof和變量替換錯誤,給定$ {正在等待一個var類型的字符串,但不會收到。感謝您的詳細解釋。 – koola

+0

也可以跳過字符串賦值,然後使用'printf'%smyDelim'「$ {array [@]}」'將一個數組轉換爲帶有任意分隔符*的分隔字符串*,不一定是單個字符。分隔符「myDelim」的最後一個實例可以通過管道到'sed -e's/myDelim $ //''中去掉,但這很麻煩。更好的想法? –

+1

@JonathanY。如果是這樣,請使用'printf -v myVar'%smyDelim'「$ {array [@]}」; myVar =「$ {myVar%myDelim}」''而不是fork到'sed' –

9

你的第一個問題已經在F. Hauri的回答中提到。下面就來加入一個數組的元素規範的方法:

ids=(1 2 3 4) 
IFS=\| eval 'lst="${ids[*]}"' 

有些人會大聲哭泣是eval是邪惡的,但它是絕對安全的位置,由於單引號。這隻具有以下優點:沒有子殼,IFS未被全局修改,它不會修剪尾隨的換行符,而且非常簡單。

0

您可以使用printf也沒有任何外部命令或需要處理IFS:

ids=(1 2 3 4) 
printf -v ids_d '|%s' "${ids[@]}" # yields "|1|2|3|4" 
ids_d=${ids_d:1}     # remove the leading '|' 
相關問題