【发布时间】:2020-06-25 03:12:56
【问题描述】:
我从下面的 api 获取字符串
/patha/pathb/pathc\r\n/patha/pathb/pathc\r\n/patha/pathb/pathc
如何将 /patha/pathb/pathc 拆分为数组中的元素?
【问题讨论】:
-
在 SO 上,我们确实鼓励用户添加他们为解决自己的问题而付出的努力;所以请添加相同的内容,然后让我们知道。
我从下面的 api 获取字符串
/patha/pathb/pathc\r\n/patha/pathb/pathc\r\n/patha/pathb/pathc
如何将 /patha/pathb/pathc 拆分为数组中的元素?
【问题讨论】:
您可以使用your_array=($(sed 's/\\r\\n/ /g' <<< $your_string))。
如果您愿意,也可以使用echo $your string | sed. . . .。要么工作正常。 echo 可能在任何地方都更具可读性和更多实现。
编辑:如果这些路径包含空格,这将是一个更好的选择 -
your_array=($(sed 's/ /~_~/g; s/\\r\\n/ /g' <<< $your_string))
i=0
for x in ${your_array[@]}; do your_array[$i]=$(sed 's/~_~/ /g' <<< $x) && let i++; done
我使用~_~ 不覆盖任何现有字符。
Edit2:这是一个更好的方法 -
temp=$(sed 's|\\r||g; s|\\|\\\\|g' <<< $your_string)
ifs=$IFS
IFS="
"
your_array=($(for x in $(eval echo -e $temp); do echo $x; done))
IFS=$ifs
【讨论】:
your_array=($(dos2unix <<<$your_string)) 会更清晰,但如果其中一个路径组件嵌入了空格,这两种解决方案都会中断,因为分词会发生在空格和换行符上。
~_~,第一个会失败。至于另一个想法,看看anubhava对this问题的回复。虽然我无法让它工作,可能是因为我正在取消 Cygwin 环境,但这种方法看起来很有希望。
\rs,而不仅仅是每个文件名末尾的那些(在\r\n 的上下文中),并且我怀疑它会使您暴露于恶意代码执行礼貌eval.
:>arr=$(echo "/patha/pathb/pathc\r\n/patha/pathb/pathc\r\n/patha/pathb/pathc" | tr '\\r\\n' '\n' | grep -v '^$')
:>for i in $arr
> do
> echo $i
> done
/patha/pathb/pathc
/patha/pathb/pathc
/patha/pathb/pathc
:>
使用tr
【讨论】:
tr 将其参数视为单个字符,而不是字符串。每次都会给他带来无法预料的结果。
echo 'this is a line\nthis is another line' | tr '\\n' ' ' 的输出不会是“这是一行这是另一行”。它将是“这是一个谎言,这是另一个谎言”。
$ str='/patha/pathb/pathc\r\n/patha/pathb/pathc\r\n/patha/pathb/pathc'
$ readarray -t -d $'\n' arr < <(sed 's/\\r\\n/\n/g' <<< "$str")
$ declare -p arr
declare -a arr=([0]="/patha/pathb/pathc" [1]="/patha/pathb/pathc" [2]="/patha/pathb/pathc")
以上内容适用于任何 str 的值,路径中的换行符除外 - 如果这对您来说是个问题,请弄清楚如何使用 \0 (NUL) 而不是 \n 作为路径分隔符。
不知道为什么我无法使用 NUL 作为分隔符:
$ readarray -t -d $'\0' arr < <(sed 's/\\r\\n/\0/g' <<< "$str")
$ declare -p arr
declare -a arr=([0]=$'/patha/pathb/pathc\\r\\n/patha/pathb/pathc\\r\\n/patha/pathb/pathc\n')
这些的一些变体也不起作用,所以我可以避免调用 sed:
$ echo "${str//\\r\\n/\n}"
/patha/pathb/pathcn/patha/pathb/pathcn/patha/pathb/pathc
$ echo "${str//\\r\\n/"$'\n'"}"
/patha/pathb/pathc$'\n'/patha/pathb/pathc$'\n'/patha/pathb/pathc
$ echo "${str//\\r\\n/"$(printf $'\n')"}"
/patha/pathb/pathc/patha/pathb/pathc/patha/pathb/pathc
【讨论】:
--null-data 添加到sed 会有所帮助?
您可以使用本地范围的 IFS 创建一个数组。
my_str=$'a\r\nb\r\nc\r\n'
IFS=$'\r\n' arr=($(echo "$my_str"))
printf "%s" ${arr[0]} | hexdump -C
00000000 61 |a|
00000001
从本地 IFS 中删除 \r 后重试以查看差异。
IFS=$'\n' arr=($(echo "$my_str"))
printf "%s" ${arr[0]} | hexdump -C
00000000 61 0d |a.|
00000002
【讨论】: