Answers:
使用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
$ echo $FILE
my_user/my_folder/file.csv
$ A="$(cut -d'/' -f2 <<<"$FILE")"
$ echo $A
[file]*
您知道这里发生了什么吗?
echo "${s##*_}"
仅使用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
unset IFS
不会返回IFS
默认值。如果在那之后有人OldIFS="$IFS"
在OldIFS中将有一个空值。同样,假设IFS的先前值为默认值,这很可能(并且非常有用)不是默认值。唯一正确的解决方案是存储在old="$IFS"
IFS =“ $ old”中,然后再还原。或者...使用子外壳(...)
。或者,更好的是,阅读我的答案。
unset IFS
不会还原IFS
为默认值,但是它将字段拆分恢复为默认效果。是的,这是一个限制,但实际上通常是可以接受的。子外壳的问题是我们需要从中获取数据。我确实展示了一个解决方案,该解决方案最终不会更改状态read
。(它可以在POSIX shell中使用,但是IIRC不能在Bourne shell中使用,因为read
由于here-document ,它将在子shell中运行。)<<<
在您的答案中使用as是仅在ksh / bash / zsh中起作用的一种变体。
user/my_folder/[this_is_my_file]*
?当我按照这些步骤操作时,我得到的是[this_is_my_file]*
/
。
最简单的方法(对于带有<<<的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
(路径名扩展)问题位置参数(“ $ @”)没有更改。
对于可移植到所有 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中工作。
read
只要OP不想从长字符串中提取第76和127个元素,使用的解决方案
readarray
在这种情况下可能更容易使用。
有了zsh
你可以分割字符串(上_
)到一个数组:
elements=(${(s:_:)string})
然后通过数组索引访问每个元素:
print -r ${elements[4]}
请记住,zsh
(不同于ksh
/ bash
)数组中的索引从1开始。
set -f
在第一个解决方案中添加警告。... *
也许是星号?
set -f
?我没有使用read
/ IFS
。尝试使用类似*_*_*
或类似字符串的解决方案...
是否允许使用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
另一个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}'`
...依此类推...