通过分隔符分割字符串并获得第 N 个元素

Ale*_*lex 150 ksh string cut split

我有一个字符串:

one_two_three_four_five
Run Code Online (Sandbox Code Playgroud)

我需要从上面的字符串中保存一个变量Atwo和变量Bfour

我正在使用 ksh。

hee*_*ayl 218

使用cutwith_作为字段分隔符并获得所需的字段:

A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"
Run Code Online (Sandbox Code Playgroud)

您还可以使用echo和管道代替 Here 字符串:

A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"
Run Code Online (Sandbox Code Playgroud)

例子:

$ s='one_two_three_four_five'

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

$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four
Run Code Online (Sandbox Code Playgroud)

要注意的是,如果$s包含换行符,将返回一个包含2一个多行字符串/ 4在每行场$s,而不是2/ 4在字段$s

  • 如果您只想要最后一个字段,则仅使用 shell 内置函数 - 无需指定其位置,或者当您不知道字段的数量时: `echo "${s##*_}"` (2认同)

Pau*_*ans 41

想看到awk答案,所以这里有一个:

A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')  
Run Code Online (Sandbox Code Playgroud)

在线试试吧!

  • 如果您想要最后一块 - 无需指定其位置或当您不知道字段数时:`awk -F_ '{print $NF}' &lt;&lt;&lt; 'one_two_3_4_five'` (4认同)
  • 这正是我要找的!!!非常感谢,这是最简单直接的方法。 (2认同)

Gil*_*il' 34

仅使用 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#*_}"
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用不带引号的参数替换并禁用通配符扩展并将其IFS设置为分隔符(这仅适用于分隔符是单个非空白字符或任何空白序列是分隔符的情况)。

string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS
Run Code Online (Sandbox Code Playgroud)

这破坏了位置参数。如果在函数中执行此操作,则只会影响函数的位置参数。

不包含换行符的字符串的另一种方法是使用read内置。

IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF
Run Code Online (Sandbox Code Playgroud)


ImH*_*ere 11

这里字符串

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

 IFS='_' read -r a second a fourth a <<<"$string"
Run Code Online (Sandbox Code Playgroud)

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

在完整脚本中:

 string='one_two_three_four_five'
 IFS='_' read -r a second a fourth a <<<"$string"
 echo "$second $fourth"
Run Code Online (Sandbox Code Playgroud)

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


Heredoc
对于可移植到所有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"
Run Code Online (Sandbox Code Playgroud)

了解此解决方案(here-doc 和 的使用都<<<将删除所有尾随换行符。
并且这是为“单行”变量内容而设计的。
多行的解决方案是可能的,但需要更复杂的结构。


Bash 4.4+
在 bash 4.4 版中可以实现一个非常简单的解决方案

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

echo "array ${arr[1]} ${arr[3]}"   # array numbers are zero based.
Run Code Online (Sandbox Code Playgroud)

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

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

set -f; IFS=_; arr=($string)
Run Code Online (Sandbox Code Playgroud)

但是有很多额外的管道来保持和重置变量和选项:

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

IFS=$oldIFS

echo "two=${arr[1]} four=${arr[3]}"
Run Code Online (Sandbox Code Playgroud)

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

set -F; IFS=_; arr=( $(echo $string) )
echo "two=${arr[2]} four=${arr[4]}"
Run Code Online (Sandbox Code Playgroud)


don*_*sti 7

随着zsh您可以将字符串(上拆分_)到一个数组:

non_empty_elements=(${(s:_:)string})
all_elements=("${(@s:_:)string}")
Run Code Online (Sandbox Code Playgroud)

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

print -r -- ${all_elements[4]}
Run Code Online (Sandbox Code Playgroud)

请记住,在zsh(与大多数其他 shell 一样,但与ksh/不同bash数组索引从 1 开始

或者直接在一个扩展中:

print -r -- "${${(@s:_:)string}[4]}"
Run Code Online (Sandbox Code Playgroud)


小智 5

是否允许使用 python 解决方案?

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

# python3 -c "import sys; print(sys.argv[1].split('_')[3])" one_two_three_four_five
four
Run Code Online (Sandbox Code Playgroud)