在变量中使用分隔符获取单词索引



给定line,delimiterword,我想根据分隔符获得该词在行中的索引位置。尽可能简单/简短。所以对于:

line="this-is-a-line_with-some.txt" 
delimiter="-" 
word="some"

echo <code goes here>
# should come out as 4

当然,我可以用一个数组拆分它,并使用for循环打印第一次出现的单词,如下所示:

line="this-is-a-line_with-some.txt" 
delimiter="-" 
word="some"
index=0
IFS="$delimiter" read -ra ary <<<"$line"
for i in "${ary[@]}"; do
if [[ $i == ${word}* ]]; then echo $index ; break ; fi
index=$((index+1))
done

但我肯定有一个更简单的解决办法。

simple解决方案。

用换行符替换分隔符,用grep获取行号。

<<<"$line" tr "$delimiter" 'n' | grep -n "$word" | cut -d: -f1

- 1:

<<<"$line" tr "$delimiter" 'n' | grep -n "$word" | cut -d: -f1 | awk '{print $1 - 1}'
# shorter
<<<"$line" tr "$delimiter" 'n' | grep -n "$word" | awk -F: '{print $1-1}'

或者直接awk:

<<<"$line" awk -v RS="$delimiter" -v word="$word" '$0 ~ word{print NR-1}'

从OP的代码和/或注释中理解:

  • 查找第一个出现以${word}
  • 开头的${delimiter}分隔字段
  • 位置索引以0为基础
  • 如果没有找到${word},则生成no输出

OP的代码可以通过使用数组的基于0的索引进一步减少(即,消除对index变量的需要):

IFS="$delimiter" read -ra ary <<<"$line"
for i in "${!ary[@]}"
do
[[ "${ary[i]}" == ${word}* ]] && echo "${i}" && break
done
# line="this-is-a-line_with-some.txt"
4
# line="a-some_def-xy-some.pdf"
1

注意:如果没有找到${word},这将生成no输出


来自superuser的参数替换解决方案的变化:

newline="${line%%${word}*}"                               # truncate string from 1st occurrence of ${word}
if [[ "${newline}" != "{line}" ]]                         # if strings are different then we found ${word}
then
IFS="${delimiter}" words_before=( ${newline} )        # break remaining string by "${delimiter}" and
# store in array words_before[]
echo "${#words_before[@]}"                            # number of array entries == index of 1st occurrence of ${word}
fi
# line="this-is-a-line_with-some.txt"
4
# line="a-some_def-xy-some.pdf"
1

注意:如果没有找到${word},这将生成no输出


一个awk的想法:

awk -F"${delimiter}" -v ptn="${word}" '{for (i=1;i<=NF;i++) if (index($i,ptn) == 1) {print i-1; exit}}' <<< "${line}"
# line="this-is-a-line_with-some.txt"
4
# line="a-some_def-xy-some.pdf"
1

或者使用内联替换ptn/${word}:

awk -F"${delimiter}" '{for (i=1;i<=NF;i++) if ($i ~ /^'"${word}"'/) {print i-1; exit}}' <<< "${line}"
# line="this-is-a-line_with-some.txt"
4
# line="a-some_def-xy-some.pdf"
1

注意:如果没有找到${word},这些awk脚本将生成no输出


要获得真正最短代码的想法,OP可以尝试发布@ codegolf,尽管真正简短的答案可能需要定位/安装新软件(库和/或二进制文件)

无需循环或外部工具的解决方案:

line="$delimiter$line"; lin2="${line%$delimiter$word*}"
if  test "$lin2" != "$line"; then
IFS="$delimiter" read -ra ary <<<"${lin2#$delimiter}"
echo ${#ary[@]}
fi

最新更新