我有三组以字符串分隔的变量,如下所示:
listNames="tom~susan~stafano~isabella"
listAges="23~45~34~10"
listNationality="british~american~italian~spanish"
我还有一个要在这些列表中删除的目标变量,即
targetName="susan"
如果目标名称是“susan”,那么我希望在所有变量中删除元素的索引,所以它最终看起来像这样。请注意,我的意思是在较大字符串中某些子字符串的位置上的“索引”,而不是与数组关联的传统意义上的“索引”:
listNames="tom~stafano~isabella"
listAges="23~34~10"
listNationality="british~italian~spanish"
如何在 Bash 中实现它?特别是因为我需要像上面一样以字符串格式保留变量(而不是将它们转换为显式数组结构,因为它们会以上述格式传递到另一个脚本中)。
答案 0 :(得分:2)
将字符串拆分为数组、删除匹配元素然后重新创建字符串的示例:
#!/usr/bin/env bash
listNames="tom~susan~stafano~isabella"
listAges="23~45~34~10"
listNationality="british~american~italian~spanish"
targetName=susan
# Use tilde instead of whitespace as field delimiter
IFS="~"
# Split into arrays
read -r -a aNames <<<"$listNames"
read -r -a aAges <<<"$listAges"
read -r -a aNationality <<<"$listNationality"
# Look for susan and delete the corresponding elements
nNames=${#aNames[@]}
for (( i = 0; i < nNames; i++)); do
if [[ ${aNames[i]} == "$targetName" ]]; then
unset "aNames[i]"
unset "aAges[i]"
unset "aNationality[i]"
fi
done
# Turn back into strings;
# ${foo[*]} puts the value of IFS between elements of foo
listNames=${aNames[*]}
listAges=${aAges[*]}
listNationality=${aNationality[*]}
# Output them for example's sake
declare -p listNames listAges listNationality
答案 1 :(得分:1)
这是另一种没有 @Shawn
使用的unset
的解决方案
#!/usr/bin/env bash
listNames="tom~susan~stafano~isabella"
listAges="23~45~34~10"
listNationality="british~american~italian~spanish"
targetName="stafano"
to_loop=0
while IFS='~' read -ra line; do
if ((!to_loop)); then
for i in "${!line[@]}"; do
[[ ${line[i]} == "$targetName" ]] &&
index=$i && break
done
fi
to_loop=1
line=("${line[*]/"${line[index]}"}")
line=("${line[*]// /\~}")
line=("${line[*]/~~/\~}")
line=("${line[*]%\~}")
values+=("${line[*]#\~}")
done < <(
printf '%s\n' "$listNames" "$listAges" "$listNationality"
)
var_names=( listNames listAges listNationality)
##: Just to show the OLD values of the variables not needed in the script
declare -p listNames listAges listNationality; printf '\n'
##: loop through the variable names and assign the new values.
for j in "${!var_names[@]}"; do
printf -v new_values '%s=%s' "${var_names[j]}" "${values[j]}"
declare "$new_values"
done
##: Just to show the NEW values of the variables not needed in the script
declare -p listNames listAges listNationality
输出
declare -- listNames="tom~susan~stafano~isabella"
declare -- listAges="23~45~34~10"
declare -- listNationality="british~american~italian~spanish"
declare -- listNames="tom~stafano~isabella"
declare -- listAges="23~34~10"
declare -- listNationality="british~italian~spanish"
使用 unset
这就是我要做的。 (@Shawn 在他的回答中使用)
#!/usr/bin/env bash
listNames="tom~susan~stafano~isabella"
listAges="23~45~34~10"
listNationality="british~american~italian~spanish"
to_loop=0
while IFS='~' read -ra line; do
if ((!to_loop)); then
for i in "${!line[@]}"; do
[[ ${line[i]} == "$targetName" ]] &&
index=$i && break
done
fi
to_loop=1
unset 'line[index]'
values+=("${line[*]}")
done < <(
printf '%s\n' "$listNames" "$listAges" "$listNationality"
)
var_names=( listNames listAges listNationality )
##: Just to show the OLD values of the variables not needed in the script
declare -p listNames listAges listNationality ; printf '\n'
##: loop through the variable names and assign the new values.
for j in "${!var_names[@]}"; do
printf -v new_values '%s=%s' "${var_names[j]}" "${values[j]// /\~}"
declare "$new_values"
done
##: Just to show the NEW values of the variables not needed in the script
declare -p listNames listAges listNationality