Bash使用+ =

时间:2018-02-18 17:11:18

标签: arrays bash sorting grep

我正在尝试做什么: 我将python文件名传递给我的bash脚本并尝试查找所有方法。我想对它们进行排序并以下列方式显示它们。

function_name file_name:line_number

结果按file_name排序。

简短版本: 我发现使用+ =将元素添加到我的数组时会出现一些意外行为。它看起来像我的第一个文件中的最后一个grep匹配,第二个文件中的第一个grep匹配被粘在一起。有人可以帮我找出原因吗?

长版:

我的代码:

#!/bin/bash/
for i in $*
do

    IFS=','
    #result+=($(grep -n -o -P '(?<=def).*(?=\()' $i ) )
    result+=( $(grep -n -o -P '(?<=def).*(?=\()' $i | sort -t\: -k2 | tr '\n' ',' | sed 's/.$//') )
    unset IFS
done

结果如下:

34: div 39: dot 7: drop 24: minus 19: plus 3: push 15: rot 11: swap 29: times 1: one 7: three 4: two

我想:

34: div 39: dot 7: drop 24: minus 1: one 19: plus 3: push 15: rot 11: swap 29: times 7: three 4: two

看了之后,我猜测grep只对传递给它的信息执行排序,而不是对整个结果数组执行排序。这让我相信我需要将grep中的所有结果存储在一个数组中,然后根据文件名对数组进行排序。这是我有各种各样的问题(双关语!)。

我试过了:

#!/bin/bash/

for i in $*
do

    IFS=','
    result+=($(grep -n -o -P '(?<=def).*(?=\()' $i ) )
    #result+=( $(grep -n -o -P '(?<=def).*(?=\()' $i | sort -t\: -k2 | tr '\n' ',' | sed 's/.$//') )
    unset IFS
done
#echo ${result[*]}
#for a in "${result[*]}"
#do
#       echo $a
#done
IFS=','
cheese=($(sort -t\: -k2 <<< "${result[*]}"))
unset IFS 
echo ${cheese[*]}

这更接近,但它看起来像第一个文件中的最后一个grep和第二个文件中的第一个grep卡在一起。 echo回路的输出:

34: div
39: dot 1: one
7: drop
24: minus  
19: plus
3: push
15: rot 
11: swap
7: three
29: times
4: two

如果点和一个函数粘在一起,我的排序输出是正确的:

34: div 39: dot 1: one 7: drop 24: minus 19: plus 3: push 15: rot 11: swap 7: three 29: times 4: two

输入file1:

def push(n):
    global stack
    stack = [n] + stack

def drop():
    global stack
    stack.pop(0)

def swap():
    global stack
    stack[0], stack[1] = stack[1], stack[0]

def rot():
    global stack
    stack[0], stack[2] = stack[2], stack[0]

def plus():
    global stack
    num = stack[0] + stack[1]
    stack[:2] = [num]

def minus():
    global stack
    num = stack[1] - stack[0]
    stack[:2] = [num]

def times():
    global stack
    num = stack[0] * stack[1]
    stack[:2] = [num]

def div():
    global stack
    num = stack[1] / stack[0]
    stack[:2] = num

def dot():
    global stack
    print stack.pop(0)

输入文件2:

def one():
    pass

def two():
    pass

def three():
    pass

---------- ---------- UPDATE

这是我的最终解决方案。以下回复是现货。

 #!/bin/bash

 declare -a result
 for i in "$@"
 do
while read line; # Read the input from the grep command for the current file
do
  result+=("${line} $i")
done< <( grep -n -o -P '(?<=def).*(?=\()' ${i})
done
#set up for sorting
IFS=$'\n'
#sort the results into sorted by function name
read -r -d '' -a sorted < <(sort -t: -k2 <<<"${result[*]}" && printf '\0')
unset IFS
#for loop for printing
for a in "${sorted[@]}"; do
    #set up delimiter
    IFS=' '
    #split variable a into array printout
    read -ra printout <<< "$a"
    #get rid of ":" at the end of the number
    num=$(echo "${printout[0]}" | cut -d':' -f 1)
    #print in format
    printf "%s %s:%s\n" "${printout[1]}" "${printout[2]}" "$num"
done
unset IFS

1 个答案:

答案 0 :(得分:2)

您的代码存在一些问题。

您不会添加像&#34; 1这样的元素:推送&#34;或&#34; 5:掉落&#34;在数组中,您将grep -n -o -P '(?<=def).*(?=\()' file1的COMPLETE输出推送到它。下一个输出是grep -n -o -P '(?<=def).*(?=\()' file2的COMPLETE输出,后面附有逗号。

无需在添加过程中使用IFS。具体来说,在排序过程中这会产生反作用,因为您仍希望在\n上分开,而不是在\(空格)上分开。

您应该始终将输入引用到数组中。

你应该声明数组。

如果您的输入可能包含shell globs,则应使用this answer中的信息。

这是工作脚本(您可以用echo ${sorted[*]}替换最后一行以获得与以前相同的字符串结构。)

#!/bin/bash
declare -a result
for i in "$@"
do
  while read line; # Read the input from the grep command for the current file
    do
      result+=("${line}")
    done< <( grep -n -o -P '(?<=def).*(?=\()' ${i})
done
IFS=$'\n'
read -r -d '' -a sorted < <(sort -t: -k2 <<<"${result[*]}" && printf '\0')
unset IFS
printf "[%s]\n" "${sorted[@]}"

纳入@Charles Duffy的建议,谢谢!