Split string into an array in Bash
在bash脚本中,我希望将一行拆分为多个部分,并将它们存储在一个数组中。
行:
1 | Paris, France, Europe |
我想把它们放在这样的数组中:
1 2 3 | array[0] = Paris array[1] = France array[2] = Europe |
号
我想用简单的代码,命令的速度不重要。我该怎么做?
1 | IFS=', ' read -r -a array <<<"$string" |
注意,
要访问单个元素:
1 | echo"${array[0]}" |
号
迭代元素:
1 2 3 4 | for element in"${array[@]}" do echo"$element" done |
要同时获取索引和值:
1 2 3 4 | for index in"${!array[@]}" do echo"$index ${array[index]}" done |
。
最后一个例子很有用,因为bash数组是稀疏的。换句话说,您可以删除一个元素或添加一个元素,然后索引就不连续了。
1 2 | unset"array[1]" array[42]=Earth |
要获取数组中的元素数:
1 | echo"${#array[@]}" |
。
如上所述,数组可以是稀疏的,因此不应该使用长度来获取最后一个元素。以下是您在bash 4.2及更高版本中的方法:
1 | echo"${array[-1]}" |
。
在任何版本的bash中(在2.05b之后的某个地方):
1 | echo"${array[@]: -1:1}" |
较大的负偏移选择距阵列末端更远的位置。请注意旧窗体中减号前的空格。这是必需的。
这个问题的所有答案在某种程度上都是错误的。好的。
回答错误1好的。
1 | IFS=', ' read -r -a array <<<"$string" |
1:这是对
实际上,对于真正的黏性者来说,
The shell treats each character of IFS as a delimiter, and splits the results of the other expansions into words using these characters as field terminators. If IFS is unset, or its value is exactly
, the default, then sequences of , , and at the beginning and end of the results of the previous expansions are ignored, and any sequence of IFS characters not at the beginning or end serves to delimit words. If IFS has a value other than the default, then sequences of the whitespace characters , , and are ignored at the beginning and end of the word, as long as the whitespace character is in the value of IFS (an IFS whitespace character). Any character in IFS that is not IFS whitespace, along with any adjacent IFS whitespace characters, delimits a field. A sequence of IFS whitespace characters is also treated as a delimiter. If the value of IFS is null, no word splitting occurs. Ok.
号
基本上,对于 对于OP,上一段中描述的第二个分离模式可能正是他想要的输入字符串,但我们可以非常确信我描述的第一个分离模式根本不正确。例如,如果他的输入字符串是 2:如果你被连到使用这个解决方案与一个单一的字符separator(一个世纪的itself由逗号,这也与以下,没有空间或其他baggage),如果value"的 你可以argue这unlikely到原因的问题,但仍然, subtle危害,应该avoided如果可能。它也引起了由"事实上, 3:非太明显了潜在的问题与解决方案,这是 也许"OP不会在乎这一点,但它仍然是在限制的价值认识的意义。它的reduces robustness和generality"的解决方案。 <P / S>。 这个问题可以通过solved appending虚拟trailing delimiter 输入字符串之前就到 错误的答案# 2 <P / S>。 similar理念: <P / S>。 (注:我错过了parentheses周围添加的"替代"的命令,answerer似乎有omitted。) <P / S>。 similar理念: <P / S>。 这些解决方案,利用Word的splitting在一个阵列分配到分离的字符串中的领域。funnily不够,就像 这就解决了 另外,分词后通常是文件名扩展(也称为路径名扩展,也称为globbing),如果这样做,可能会损坏包含字符 此答案的另一个问题是,所有空字段都将丢失。这可能是问题,也可能不是问题,具体取决于应用程序。好的。 注意:如果您要使用这个解决方案,最好使用参数扩展的 回答错误3好的。 这个答案几乎与2相同。不同之处在于,回答者假定字段由两个字符分隔,其中一个字符在默认的 这不是一个非常通用的解决方案。此外,可以认为逗号实际上是这里的"主要"分隔符,剥离它然后根据空格字符进行字段拆分是完全错误的。再一次,考虑我的反例: 同样,文件名扩展可能会损坏扩展的单词,但是可以通过暂时禁用 同样,所有空字段都将丢失,这可能是问题,也可能不是问题,具体取决于应用程序。好的。 回答错误4好的。 号 这类似于2和3,因为它使用分词来完成任务,只是现在代码显式地将 一个问题是,文件名扩展会破坏前面描述的受影响的单词,尽管这可以通过在 另一个潜在的问题是,由于LF符合前面定义的"IFS空白字符",所有空字段都将丢失,就像在2和3中一样。如果分隔符恰好是非"ifs空白字符",这当然不是问题,而且根据应用程序的不同,它可能无论如何都不重要,但它确实会影响解决方案的通用性。好的。 因此,总而言之,假设您有一个单字符分隔符,并且它不是一个非"ifs空白字符",或者您不关心空字段,并且您将关键语句包装在 (另外,为了便于参考,可以使用 回答错误5好的。 类似的想法:好的。 这个解决方案实际上是1(它将 另外,对于第二个变量,似乎完全不需要 号 即使简单命令涉及多个变量分配,也是如此;同样,只要没有命令字,所有变量分配都会影响shell环境:好的。 但是,如果变量赋值附加到命令名(我喜欢称之为"前缀赋值"),那么它不会影响shell环境,而是只影响已执行命令的环境,不管它是内置的还是外部的:好的。 。 bash手册中的相关引用:好的。
If no command name results, the variable assignments affect the current shell environment. Otherwise, the variables are added to the environment of the executed command and do not affect the current shell environment.
Ok. 号 利用变量分配的这一特性,我们可以暂时改变 所以,我们实际上陷入了僵局,有点像第22条军规。但是,当 所以,正如你所看到的,这实际上是一个相当聪明的技巧,并且以一种相当不明显的方式完成所需的工作(至少在任务完成方面)。实际上,我并不反对这种伎俩,尽管 但同样,由于"世界上最糟糕的"问题的聚集,这仍然是对OP要求的错误回答。好的。 回答错误6好的。 号 嗯。。。什么?OP有一个字符串变量需要解析为数组。这个"答案"以粘贴到数组文字中的输入字符串的逐字内容开始。我想这是一种方法。好的。 看起来,应答者可能假设
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 Ok. 号 因此, 让我试着让这更清楚些。我认为在解析和执行之间划出一个界限可能会比较好。bash必须首先解析源代码,这显然是一个解析事件,然后执行代码,这就是扩展进入图片的时候。扩展实际上是一个执行事件。此外,我对我刚才引用的 将命令行拆分为单词后,在命令行上执行扩展。执行了七种扩展:大括号扩展、颚化符扩展、参数和变量扩展、命令替换、算术扩展、分词和路径名扩展。好的。 扩展的顺序是:大括号扩展;tilde扩展、参数和变量扩展、算术扩展和命令替换(从左到右进行);分词;路径名扩展。好的。 您可以争辩说,GNU版本的手册做得稍微好一些,因为它在扩展部分的第一句话中选择了单词"tokens"而不是"words":好的。
Expansion is performed on the command line after it has been split into tokens.
Ok. 号 重要的是, 回答错误7好的。 这是最好的解决方案之一。注意,我们又开始使用 但也有问题。第一:当您向 这个解决方案的第二个问题是,它实际上并没有处理自定义字段分隔符的情况,例如op的逗号空间。和以前一样,不支持多字符分隔符,这是该解决方案的一个不幸限制。我们可以通过指定 可以预见,未计算的周围空白被拉入字段值中,因此必须随后通过剪裁操作更正(这也可以直接在while循环中完成)。但还有一个明显的错误:欧洲不见了!怎么了?答案是,如果 从技术上讲,同样的错误也影响了前面的例子;不同之处在于,字段分隔符被认为是lf,这是不指定 在那里,问题解决了。另一种解决方案是,只有当(1) 这种方法还揭示了由 所以,总的来说,这是一个非常强大的解决方案。唯一剩下的弱点是缺乏对多字符定界符的支持,稍后我将对此进行讨论。好的。 错误答案8好的。 (事实上,这与7来自同一个帖子;回答者在同一帖子中提供了两个解决方案。)好的。 作为 首先,为了避免这种情况的发生,请注意,正如在进行字段解析时 第二,和以前一样,它不支持多字符分隔符。我也会马上解决这个问题。好的。 第三,编写的解决方案不解析OP的输入字符串,事实上,它不能像解析那样被使用。我也会在这方面做些扩展。好的。 基于以上原因,我仍然认为这是对OP问题的"错误答案"。下面我将给出我认为正确的答案。好的。 正确答案好的。 这是NA?我试图通过指定 我们看到结果与我们从循环 号 这里的问题是 剩下的两个实际相关的问题是:(1)需要修剪的外来空白;(2)缺乏对多字符分隔符的支持。好的。 当然,空白可以在后面进行修剪(例如,参见如何从bash变量中修剪空白?)但是如果我们能破解一个多字符分隔符,那么这将一次性解决这两个问题。好的。 不幸的是,无法直接使用多字符分隔符。我想到的最佳解决方案是对输入字符串进行预处理,将多字符分隔符替换为单字符分隔符,这样可以保证不会与输入字符串的内容冲突。唯一具有此保证的字符是nul字节。这是因为,在bash中(顺便说一下,不是在zsh中),变量不能包含nul字节。这个预处理步骤可以在进程替换中以内联方式完成。下面介绍如何使用awk:好的。 终于到了!此解决方案不会在中间错误地拆分字段,不会过早地剪切,不会删除空字段,不会损坏文件名扩展名本身,不会自动删除前导和尾随的空格,不会在结尾处留下一个收起LF,不需要循环,也不会固定为单个字符分隔符。好的。 切边液好的。 最后,我想用 号好啊。
2
## declare -a a=([0]="Los" [1]="Angeles" [2]="United" [3]="States" [4]="North" [5]="America")
2
## declare -a a=([0]="" [1]="" [2]="a" [3]="" [4]="b" [5]="c" [6]="" [7]="")
2
3
set -f # avoid globbing (expansion of *).
array=(${string//:/ })
2
3
a=($(echo $t | tr ','"
"))
2
3
array=(`echo $string | sed 's/,/
/g'`)
2
arr=(${str//,/}) # delete all occurrences of ','
2
3
4
5
6
7
8
9
10
second line
third line'
oldIFS="$IFS"
IFS='
'
IFS=${IFS:0:1} # this is useful to format your code with tabs
lines=( $string )
IFS="$oldIFS"
';
2
3
4
OIFS="$IFS"
IFS=', ' array=($countries)
IFS="$OIFS"
2
IFS=', ' env; ## env is an external command, the $IFS assignment does not outlive it
2
3
IFS=' ';declare -a array=(Paris France Europe)
2
3
4
5
second line
third line'
while read -r line; do lines+=("$line"); done <<<"$string"
2
3
4
5
6
7
8
9
c d
e f '; ## input string
a=(); while read -r line; do a+=("$line"); done <<<"$string"; declare -p a;
## declare -a a=([0]="a b" [1]="c d" [2]="e f") ## read trimmed surrounding whitespace
a=(); while read -r; do a+=("$REPLY"); done <<<"$string"; declare -p a;
## declare -a a=([0]=" a b " [1]=" c d " [2]=" e f ") ## no trimming
2
3
a=(); while read -rd,; do a+=("$REPLY"); done <<<"$string"; declare -p a;
## declare -a a=([0]="Paris" [1]=" France")
2
declare -a a=([0]="Paris" [1]=" France" [2]=" Europe")
2
3
## declare -a a=([0]="Paris" [1]=" France" [2]=$' Europe
')
2
3
4
5
second line
third line'
readarray -t lines <<<"$string"
2
3
4
readarray -td, a <<<"$string"; declare -p a;
## declare -a a=([0]="Paris" [1]=" France" [2]=$' Europe
')
2
3
## declare -a a=([0]="Paris" [1]=" France" [2]=" Europe" [3]=$'
')
2
## declare -a a=([0]="Paris" [1]=" France" [2]=" Europe")
2
3
declare -p a;
## declare -a a=([0]="Paris" [1]="France" [2]="Europe")
2
3
4
5
6
function val_ltrim { if [["$val" =~ ^[[:space:]]+ ]]; then val="${val:${#BASH_REMATCH[0]}}"; fi; };
function val_rtrim { if [["$val" =~ [[:space:]]+$ ]]; then val="${val:0:${#val}-${#BASH_REMATCH[0]}}"; fi; };
function val_trim { val_ltrim; val_rtrim; };
readarray -c1 -C 'mfcb val_trim a' -td, <<<"$string,"; unset 'a[-1]'; declare -p a;
## declare -a a=([0]="Paris" [1]="France" [2]="Europe")
以下是不设置IFS的方法:
1 2 3 4 5 6 7 | string="1:2:3:4:5" set -f # avoid globbing (expansion of *). array=(${string//:/ }) for i in"${!array[@]}" do echo"$i=>${array[i]}" done |
想法是使用字符串替换:
1 | ${string//substring/replacement} |
。
要用空白替换$substring的所有匹配项,然后使用替换字符串初始化数组:
1 | (element1 element2 ... elementN) |
号
注意:这个答案使用了split+glob操作符。因此,为了防止某些字符(如
1 2 3 4 | t="one,two,three" a=($(echo"$t" | tr ',' ' ')) echo"${a[2]}" |
号
打印三张
有时我突然想到,在接受的答案中描述的方法不起作用,特别是如果分隔符是回车符。在这些情况下,我是这样解决的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | string='first line second line third line' oldIFS="$IFS" IFS=' ' IFS=${IFS:0:1} # this is useful to format your code with tabs lines=( $string ) IFS="$oldIFS" for line in"${lines[@]}" do echo"--> $line" done |
。
接受的答案适用于一行中的值。如果变量有多行:
1 2 3 | string='first line second line third line' |
号
我们需要一个非常不同的命令来获取所有行:
埃多克斯1〔2〕
或者更简单的bash readarray:
1 | readarray -t lines <<<"$string" |
号
打印所有行非常容易利用打印功能:
1 2 3 4 5 6 | printf">[%s] ""${lines[@]}" >[first line] >[ second line] >[ third line] |
号
将字符串拆分为数组的关键是
如果指定
您可以使用
1 2 3 4 5 6 7 8 9 | #!/bin/bash str="Paris, France, Europe" array=() while read -r -d $'\0' each; do # use a NUL terminated field separator array+=("$each") done < <(printf"%s""$str" | awk '{ gsub(/,[ ]+|$/,"\0"); print }') declare -p array # declare -a array=([0]="Paris" [1]="France" [2]="Europe") output |
直接在bash中使用regex更有效:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/bash str="Paris, France, Europe" array=() while [[ $str =~ ([^,]+)(,[ ]+|$) ]]; do array+=("${BASH_REMATCH[1]}") # capture the field i=${#BASH_REMATCH} # length of field + delimiter str=${str:i} # advance the string by that length done # the loop deletes $str, so make a copy if needed declare -p array # declare -a array=([0]="Paris" [1]="France" [2]="Europe") output... |
对于第二种形式,没有子shell,而且它本身就更快。
bgoldst编辑:这里有一些比较我的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | ## competitors function c_readarray { readarray -td '' a < <(awk '{ gsub(/, /,"\0"); print; };' <<<"$1,"); unset 'a[-1]'; }; function c_read { a=(); local REPLY=''; while read -r -d ''; do a+=("$REPLY"); done < <(awk '{ gsub(/, /,"\0"); print; };' <<<"$1,"); }; function c_regex { a=(); local s="$1,"; while [[ $s =~ ([^,]+),\ ]]; do a+=("${BASH_REMATCH[1]}"); s=${s:${#BASH_REMATCH}}; done; }; ## helper functions function rep { local -i i=-1; for ((i = 0; i<$1; ++i)); do printf %s"$2"; done; }; ## end rep() function testAll { local funcs=(); local args=(); local func=''; local -i rc=-1; while [["$1" != ':' ]]; do func="$1"; if [[ !"$func" =~ ^[_a-zA-Z][_a-zA-Z0-9]*$ ]]; then echo"bad function name: $func">&2; return 2; fi; funcs+=("$func"); shift; done; shift; args=("$@"); for func in"${funcs[@]}"; do echo -n"$func"; { time $func"${args[@]}">/dev/null 2>&1; } 2>&1| tr ' ' '/'; rc=${PIPESTATUS[0]}; if [[ $rc -ne 0 ]]; then echo"[$rc]"; else echo; fi; done| column -ts/; }; ## end testAll() function makeStringToSplit { local -i n=$1; ## number of fields if [[ $n -lt 0 ]]; then echo"bad field count: $n">&2; return 2; fi; if [[ $n -eq 0 ]]; then echo; elif [[ $n -eq 1 ]]; then echo 'first field'; elif [["$n" -eq 2 ]]; then echo 'first field, last field'; else echo"first field, $(rep $[$1-2] 'mid field, ')last field"; fi; }; ## end makeStringToSplit() function testAll_splitIntoArray { local -i n=$1; ## number of fields in input string local s=''; echo"===== $n field$(if [[ $n -ne 1 ]]; then echo 's'; fi;) ====="; s="$(makeStringToSplit"$n")"; testAll c_readarray c_read c_regex :"$s"; }; ## end testAll_splitIntoArray() ## results testAll_splitIntoArray 1; ## ===== 1 field ===== ## c_readarray real 0m0.067s user 0m0.000s sys 0m0.000s ## c_read real 0m0.064s user 0m0.000s sys 0m0.000s ## c_regex real 0m0.000s user 0m0.000s sys 0m0.000s ## testAll_splitIntoArray 10; ## ===== 10 fields ===== ## c_readarray real 0m0.067s user 0m0.000s sys 0m0.000s ## c_read real 0m0.064s user 0m0.000s sys 0m0.000s ## c_regex real 0m0.001s user 0m0.000s sys 0m0.000s ## testAll_splitIntoArray 100; ## ===== 100 fields ===== ## c_readarray real 0m0.069s user 0m0.000s sys 0m0.062s ## c_read real 0m0.065s user 0m0.000s sys 0m0.046s ## c_regex real 0m0.005s user 0m0.000s sys 0m0.000s ## testAll_splitIntoArray 1000; ## ===== 1000 fields ===== ## c_readarray real 0m0.084s user 0m0.031s sys 0m0.077s ## c_read real 0m0.092s user 0m0.031s sys 0m0.046s ## c_regex real 0m0.125s user 0m0.125s sys 0m0.000s ## testAll_splitIntoArray 10000; ## ===== 10000 fields ===== ## c_readarray real 0m0.209s user 0m0.093s sys 0m0.108s ## c_read real 0m0.333s user 0m0.234s sys 0m0.109s ## c_regex real 0m9.095s user 0m9.078s sys 0m0.000s ## testAll_splitIntoArray 100000; ## ===== 100000 fields ===== ## c_readarray real 0m1.460s user 0m0.326s sys 0m1.124s ## c_read real 0m2.780s user 0m1.686s sys 0m1.092s ## c_regex real 17m38.208s user 15m16.359s sys 2m19.375s ## |
这类似于JMoney38的方法,但使用的是SED:
1 2 3 4 | string="1,2,3,4" array=(`echo $string | sed 's/,/ /g'`) echo ${array[0]} |
印刷品1
纯bash多字符分隔符解决方案。
正如其他人在这个线程中指出的那样,op的问题给出了一个逗号分隔字符串的例子,将其解析为数组,但没有指出他/她是否只对逗号分隔符、单字符分隔符或多字符分隔符感兴趣。
由于谷歌倾向于将这个答案排在搜索结果的顶部或附近,所以我想为读者提供一个关于多个字符分隔符问题的强有力的答案,因为至少有一个回答中也提到了这个问题。
如果你在寻找一个多字符定界符问题的解决方案,我建议你回顾一下Mallikarjun M的文章,特别是gniourf的回复。谁使用参数扩展提供了这个优雅的纯bash解决方案:
1 2 3 4 5 6 7 8 9 10 | #!/bin/bash str="LearnABCtoABCSplitABCaABCString" delimiter=ABC s=$str$delimiter array=(); while [[ $s ]]; do array+=("${s%%"$delimiter"*}" ); s=${s#*"$delimiter"}; done; declare -p array |
引用评论/参考文章链接
链接到引用的问题:如何在bash中拆分多字符分隔符上的字符串?
我在分析输入时遇到了这篇文章,比如:单词1,单词2,…
以上都没有帮助我。用锥子解决了这个问题。如果它能帮助某人:
1 2 3 4 5 6 7 | STRING="value1,value2,value3" array=`echo $STRING | awk -F ',' '{ s = $1; for (i = 2; i <= NF; i++) s = s" "$i; print s; }'` for word in ${array} do echo"This is the word $word" done |
。
试试这个
1 2 | IFS=', '; array=(Paris, France, Europe) for item in ${array[@]}; do echo $item; done |
号
很简单。如果需要,还可以添加声明(也可以删除逗号):
1 | IFS=' ';declare -a array=(Paris France Europe) |
号
添加ifs是为了撤消上面的操作,但是在新的bash实例中没有它就可以工作。
更新:不要这样做,因为Eval有问题。
仪式稍微少一点:
1 | IFS=', ' eval 'array=($string)' |
号
例如
1 2 3 | string="foo, bar,baz" IFS=', ' eval 'array=($string)' echo ${array[1]} # -> bar |
号
使用此:
1 2 3 4 5 6 7 8 | countries='Paris, France, Europe' OIFS="$IFS" IFS=', ' array=($countries) IFS="$OIFS" #${array[1]} == Paris #${array[2]} == France #${array[3]} == Europe |
号
这对我在OSX上有效:
1 2 | string="1 2 3 4 5" declare -a array=($string) |
如果字符串具有不同的分隔符,只需首先用空格替换这些分隔符:
1 2 3 | string="1,2,3,4,5" delimiter="," declare -a array=($(echo $string | tr"$delimiter""")) |
。
简单:—)
这是我的黑客!
用字符串分割字符串是使用bash非常无聊的事情。会发生的是,我们的方法有限,只能在少数情况下工作(按";","/","等等分割),或者我们在输出中有各种副作用。
下面的方法需要一些操作,但我相信它可以满足我们的大多数需求!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | #!/bin/bash # -------------------------------------- # SPLIT FUNCTION # ---------------- F_SPLIT_R=() f_split() { : 'It does a"split" into a given string and returns an array. Args: TARGET_P (str): Target string to"split". DELIMITER_P (Optional[str]): Delimiter used to"split". If not informed the split will be done by spaces. Returns: F_SPLIT_R (array): Array with the provided string separated by the informed delimiter. ' F_SPLIT_R=() TARGET_P=$1 DELIMITER_P=$2 if [ -z"$DELIMITER_P" ] ; then DELIMITER_P="" fi REMOVE_N=1 if ["$DELIMITER_P" ==" " ] ; then REMOVE_N=0 fi # NOTE: This was the only parameter that has been a problem so far! # By Questor # [Ref.: https://unix.stackexchange.com/a/390732/61742] if ["$DELIMITER_P" =="./" ] ; then DELIMITER_P="[.]/" fi if [ ${REMOVE_N} -eq 1 ] ; then # NOTE: Due to bash limitations we have some problems getting the # output of a split by awk inside an array and so we need to use #"line break" ( ) to succeed. Seen this, we remove the line breaks # momentarily afterwards we reintegrate them. The problem is that if # there is a line break in the"string" informed, this line break will # be lost, that is, it is erroneously removed in the output! # By Questor TARGET_P=$(awk 'BEGIN {RS="dn"} {gsub(" ","3F2C417D448C46918289218B7337FCAF"); printf $0}' <<<"${TARGET_P}") fi # NOTE: The replace of" " by"3F2C417D448C46918289218B7337FCAF" results # in more occurrences of"3F2C417D448C46918289218B7337FCAF" than the # amount of" " that there was originally in the string (one more # occurrence at the end of the string)! We can not explain the reason for # this side effect. The line below corrects this problem! By Questor TARGET_P=${TARGET_P%????????????????????????????????} SPLIT_NOW=$(awk -F"$DELIMITER_P" '{for(i=1; i<=NF; i++){printf"%s ", $i}}' <<<"${TARGET_P}") while IFS= read -r LINE_NOW ; do if [ ${REMOVE_N} -eq 1 ] ; then # NOTE: We use"'" to prevent blank lines with no other characters # in the sequence being erroneously removed! We do not know the # reason for this side effect! By Questor LN_NOW_WITH_N=$(awk 'BEGIN {RS="dn"} {gsub("3F2C417D448C46918289218B7337FCAF"," "); printf $0}' <<<"'${LINE_NOW}'") # NOTE: We use the commands below to revert the intervention made # immediately above! By Questor LN_NOW_WITH_N=${LN_NOW_WITH_N%?} LN_NOW_WITH_N=${LN_NOW_WITH_N#?} F_SPLIT_R+=("$LN_NOW_WITH_N") else F_SPLIT_R+=("$LINE_NOW") fi done <<<"$SPLIT_NOW" } # -------------------------------------- # HOW TO USE # ---------------- STRING_TO_SPLIT=" * How do I list all databases and tables using psql? " sudo -u postgres /usr/pgsql-9.4/bin/psql -c "\l" sudo -u postgres /usr/pgsql-9.4/bin/psql <DB_NAME> -c "\dt" " " \list or \l: list all databases \dt: list all tables in the current database " [Ref.: https://dba.stackexchange.com/questions/1285/how-do-i-list-all-databases-and-tables-using-psql] " f_split"$STRING_TO_SPLIT""bin/psql -c" # -------------------------------------- # OUTPUT AND TEST # ---------------- ARR_LENGTH=${#F_SPLIT_R[*]} for (( i=0; i<=$(( $ARR_LENGTH -1 )); i++ )) ; do echo"> -----------------------------------------" echo"${F_SPLIT_R[$i]}" echo" < -----------------------------------------" done if ["$STRING_TO_SPLIT" =="${F_SPLIT_R[0]}bin/psql -c${F_SPLIT_R[1]}" ] ; then echo"> -----------------------------------------" echo"The strings are the same!" echo" < -----------------------------------------" fi |
另一种不修改IFS的方法是:
1 | read -r -a myarray <<<"${string//, /$IFS}" |
号
我们可以通过
但对于非常大的弦来说,这可能会很慢?
这是基于丹尼斯·威廉姆森的回答。
另一种方法是:
1 2 | string="Paris, France, Europe" IFS=', ' arr=(${string}) |
号
现在元素存储在"arr"数组中。要遍历元素,请执行以下操作:
1 | for i in ${arr[@]}; do echo $i; done |
另一种方法是:
1 2 | str="a, b, c, d" # assuming there is a space after ',' as in Q arr=(${str//,/}) # delete all occurrences of ',' |
。
在这个"arr"之后是一个包含四个字符串的数组。这不需要处理ifs或read或任何其他特殊的东西,因此更简单和直接。