it-swarm.cn

用定界符分割字符串并获取第N个元素

我有一个字符串:

one_two_three_four_five

我需要从上述字符串中将变量Atwo保存到变量Bfour

96
Alex

cut_作为字段定界符,并获取所需的字段:

A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"

您也可以使用echo并使用管道代替Here字符串:

A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"

例如:

$ s='one_two_three_four_five'

$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two

$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four
144
heemayl

仅使用POSIX sh构造,就可以使用 参数替换构造 一次解析一个定界符。请注意,此代码假定存在必需的字段数,否则将重复最后一个字段。

string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"

另外,您也可以使用无引号的参数替换,并禁用 通配符扩展 ,并且将 IFS设置为分隔符 (仅当分隔符为单个非空格字符或任何空格序列作为分隔符)。

string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS

这使位置参数变得混乱。如果在函数中执行此操作,则仅影响函数的位置参数。

另一种方法是使用read内置函数。

IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF
27

想要看到一个awk答案,所以这是一个:

A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')
21
Paul Evans

最简单的方法(对于带有<<<的shell)是:

 IFS='_' read -r a second a fourth a <<<"$string"

使用时间变量$a而不是$_,因为一个Shell抱怨。

在完整脚本中:

 string='one_two_three_four_five'
 IFS='_' read -r a second a fourth a <<<"$string"
 echo "$second $fourth"

没有IFS更改,set -f没有问题(路径名扩展)位置参数(“ $ @”)没有更改。


对于可移植到all shell(是的,包括所有POSIX)而无需更改IFS或set -f的解决方案,请使用(稍微复杂一点)heredoc等效项:

string='one_two_three_four_five'

IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_

echo "$second $fourth"

请理解,此解决方案(here-doc和<<<的使用都会删除所有尾随的换行符。
这是为了“一个衬里”可变内容而设计的。
可以使用多个衬套的解决方案,但需要更复杂的构造。


Bash 4.4版中可能有一个非常简单的解决方案

readarray -d _ -t arr <<<"$string"

echo "array ${arr[1]} ${arr[3]}"   # array numbers are zero based.

POSIX Shell没有等效项,因为许多POSIX Shell没有数组。

对于具有数组的shell可能很简单:
(经测试可以在attsh,lksh,mksh,ksh和bash中工作)

set -f; IFS=_; arr=($string)

但是还有很多其他方法可以保留和重置变量和选项:

string='one_* *_three_four_five'

case $- in
    *f*) noglobset=true; ;;
    *) noglobset=false;;
esac

oldIFS="$IFS"

set -f; IFS=_; arr=($string)

if $noglobset; then set -f; else set +f; fi

echo "two=${arr[1]} four=${arr[3]}"

在zsh中,数组从1开始,默认情况下不拆分字符串。
因此,需要进行一些更改才能在zsh中正常工作。

11
Isaac

使用zsh,您可以分割字符串(在_)放入数组:

elements=(${(s:_:)string})

然后通过数组索引访问每个元素:

print -r ${elements[4]}

请记住,在zsh中(与ksh/bash不同) 数组索引从1开始

3
don_crissti

是否可以使用python解决方案?

# python -c "import sys; print sys.argv[1].split('_')[1]" one_two_three_four_five
two

# python -c "import sys; print sys.argv[1].split('_')[3]" one_two_three_four_five
four
2
fhgd

另一个awk示例;更易于理解。

A=\`echo one_two_three_four_five | awk -F_ '{print $1}'\`  
B=\`echo one_two_three_four_five | awk -F_ '{print $2}'\`  
C=\`echo one_two_three_four_five | awk -F_ '{print $3}'\`  
... and so on...  

也可以与变量一起使用。
假设:
this_str =“ one_two_three_four_five”
然后进行以下工作:
A =`echo $ {this_str} | awk -F_'{print $ 1}'`
B =`echo $ {this_str} | awk -F_'{print $ 2}'`
C =`echo $ {this_str} | awk -F_'{print $ 3}'`
... 等等...

1
user274900