英文:
How to fill array with strings which can contain multiple lines in Bash?
问题
I'm having a variable with multiple strings, which can contain multiple lines:
var="foo 'bar baz' 'lorem
ipsum'"
I need all of them as array elements, so my idea was to use xargs -n1
to read every quoted or unquoted string into separate array elements:
mapfile -t arr < <(xargs -n1 <<< "$(echo "$var")")
But this causes this error:
xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option
Finally the only idea I had, was to replace the line feed against a carriage return and restore it afterwards:
# fill array preserve line feed (dirty)
mapfile -t arr < <(xargs -n1 <<< "$(echo "$var" | tr '\n' '\r')")
# restore line feed
for (( i=0; i<${#arr[@]}; i++ )); do
arr[i]=$(echo "${arr[$i]}" | tr '\r' '\n')
done
It works:
# for (( i=0; i<${#arr[@]}; i++ )); do echo "index: $i, value: ${arr[$i]}"; done
index: 0, value: foo
index: 1, value: bar baz
index: 2, value: lorem
ipsum
But only as long the input variable does not contain a carriage return.
I assume I need xargs
output every result delimited by a null byte and import with mapfile
's -d ''
, but it seems xargs
is missing a print0
option (tr '\n' '\0'
would manipulate the multi-line string itself).
英文:
I'm having a variable with multiple strings, which can contain multiple lines:
var="foo 'bar baz' 'lorem
ipsum'"
I need all of them as array elements, so my idea was to use xargs -n1
to read every quoted or unquoted string into separate array elements:
mapfile -t arr < <(xargs -n1 <<< "$(echo "$var")" )
But this causes this error:
xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option
Finally the only idea I had, was to replace the line feed against a carriage return and restore it afterwards:
# fill array preserve line feed (dirty)
mapfile -t arr < <(xargs -n1 <<< "$(echo "$var" | tr '\n' '\r')" )
# restore line feed
for (( i=0; i<${#arr[@]}; i++ )); do
arr[i]=$(echo "${arr[$i]}" | tr '\r' '\n')
done
It works:
# for (( i=0; i<${#arr[@]}; i++ )); do echo "index: $i, value: ${arr[$i]}"; done
index: 0, value: foo
index: 1, value: bar baz
index: 2, value: lorem
ipsum
But only as long the input variable does not contain a carriage return.
I assume I need xargs
output every result delimited by a null byte and import with mapfile
's -d ''
, but it seems xargs
is missing a print0
option (tr '\n' '\0'
would manipulate the multi-line string itself).
答案1
得分: 1
这是清理过的代码,演示了如何使用Bash正则表达式从字符串中提取部分内容:
#!/bin/bash -p
var="foo 'bar baz' 'lorem
ipsum'"
leadspace_rx='^[[:space:]]+(.*)$'
bare_rx="^([^'[:space:]]+)(.*)$"
quoted_rx="^'([^']*)'(.*)$"
arr=()
while [[ -n $var ]]; do
if [[ $var =~ $leadspace_rx ]]; then
var=${BASH_REMATCH[1]}
elif [[ $var =~ $bare_rx ]]; then
arr+=( "${BASH_REMATCH[1]}" )
var=${BASH_REMATCH[2]}
elif [[ $var =~ $quoted_rx ]]; then
arr+=( "${BASH_REMATCH[1]}" )
var=${BASH_REMATCH[2]}
else
printf 'ERROR: Cannot handle: %s\n' "$var" >&2
exit 1
fi
done
declare -p arr
输出结果是 declare -a arr=([0]="foo" [1]="bar baz" [2]=$'lorem\nipsum')
。如果您认为这个想法值得追求,可以轻松将字符串拆分的代码封装到一个函数中。当前的代码可能会执行一些出乎意料的操作,例如,字符串 a'b'c
被转换为数组 (a b c)
。如果您能提供更精确的输入字符串格式规范,我可以尝试修改代码来处理它。
英文:
This Shellcheck-clean code demonstrates a way to do it by using Bash regular expressions to extract parts from the string:
#! /bin/bash -p
var="foo 'bar baz' 'lorem
ipsum'"
leadspace_rx='^[[:space:]]+(.*)$'
bare_rx="^([^'[:space:]]+)(.*)$"
quoted_rx="^'([^']*)'(.*)$"
arr=()
while [[ -n $var ]]; do
if [[ $var =~ $leadspace_rx ]]; then
var=${BASH_REMATCH[1]}
elif [[ $var =~ $bare_rx ]]; then
arr+=( "${BASH_REMATCH[1]}" )
var=${BASH_REMATCH[2]}
elif [[ $var =~ $quoted_rx ]]; then
arr+=( "${BASH_REMATCH[1]}" )
var=${BASH_REMATCH[2]}
else
printf 'ERROR: Cannot handle: %s\n' "$var" >&2
exit 1
fi
done
declare -p arr
- The output is
declare -a arr=([0]="foo" [1]="bar baz" [2]=$'lorem\nipsum')
- The code for splitting up a string could easily be encapsulated in a function if you think this idea is worth pursuing.
- The current code does things that you might not expect. For instance, the string
a'b'c
is converted to the array(a b c)
. If you can provide a more precise specification for the format of input strings I'll see if the code can be modified to handle it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论