Formatting text in BASH

I am completely new to Shell scripting. My task is to make a script that shows the functions used in the file (caller and callee). I used objdump, grep, awk etc. to get this output:

000000000040090d <usage>:
000000000040095d <failure>:
  400970:   e8 98 ff ff ff          callq  40090d <usage>
000000000040097f <strton>:
  4009bc:   e8 9c ff ff ff          callq  40095d <failure>
00000000004009c6 <main>:
  400a0e:   e8 6c ff ff ff          callq  40097f <strton>
  400a26:   e8 32 ff ff ff          callq  40095d <failure>
  400a41:   e8 39 ff ff ff          callq  40097f <strton>
  400a59:   e8 ff fe ff ff          callq  40095d <failure>
  400a9a:   e8 be fe ff ff          callq  40095d <failure>
  400aae:   e8 cc fe ff ff          callq  40097f <strton>
  400ac2:   e8 b8 fe ff ff          callq  40097f <strton>
  400ad1:   e8 87 fe ff ff          callq  40095d <failure>
  400afe:   e8 fe 01 00 00          callq  400d01 <set_timeout>
  400b1c:   e8 3c fe ff ff          callq  40095d <failure>
  400b26:   e8 19 00 00 00          callq  400b44 <print_fib_upto>
  400b37:   e8 89 00 00 00          callq  400bc5 <print_ackermann>

Well, the result should look like this:

failure -> usage
strton -> failure
main -> failure
main -> print_ackermann
main -> print_fib_upto
main -> set_timeout
main -> strton

But I do not know how to do this. I know how to do this in C, etc., but not here. I think this is the correct pseudo code.

If (end of line == ">:")
         caller == last column;
         while (end of line == ">") {
                   callee == last column;
                   echo "$caller -> $callee"
         }

Can someone tell me how to write this in BASH? Thanks a lot, Maybe this is a stupid question, but I still don't know what to do with the shell.

+4
source share
6 answers

You can use awk:

awk -F'[<>:]+' 'NF==3{p=$(NF-1); next} {print p, "->", $(NF-1)}' file
failure -> usage
strton -> failure
main -> strton
main -> failure
main -> strton
main -> failure
main -> failure
main -> strton
main -> strton
main -> failure
main -> set_timeout
main -> failure
main -> print_fib_upto
main -> print_ackermann
+2
source

For instance:

#!/bin/bash    
while read -r line
do
    case "$line" in
        *:) caller=$line; continue;;
        *)  echo "$caller $line";;
    esac
done < <(sed 's/.*</</' < caldata) | sed 's/[<>]//g;s/:/ -> /' | sort -u

gives:

failure ->  usage
main ->  failure
main ->  print_ackermann
main ->  print_fib_upto
main ->  set_timeout
main ->  strton
strton ->  failure
+4

, awk, bash.

while read; do # If not given an argument `read` puts the line into `REPLY`
  case $REPLY in # Use a case expression for pattern matching.
    *>:) caller="${REPLY##*<}"
         caller="${caller%>:}" # Parameter expansions to strip off unwanted parts of the line.
         ;;
    *>) callee="${REPLY##*<}"
        callee="${callee%>}"
        ;;
  esac
  echo "$caller -> $callee"
done
+2

awk:

$ awk 'NF==2 {
    gsub(/[[:punct:]]/, "", $NF)
    caller = $NF
    next
}
{
    gsub(/[[:punct:]]/, "", $NF)
    map[caller,$NF]++
}
END {
    for(calls in map) {
        n = split(calls, tmp, SUBSEP)
        print tmp[1]" -> "tmp[2]
    }
}' file
main -> printackermann
main -> settimeout
strton -> failure
main -> printfibupto
main -> failure
failure -> usage
main -> strton

$ awk '
NF==2 {
    for(keys in map) 
        print map[keys]" -> "keys;
    delete map
    gsub(/[[:punct:]]/, "", $NF)
    caller = $NF
    next
}
{
    gsub(/[[:punct:]]/, "", $NF)
    map[$NF] = caller
}
END {
    for(keys in map)  
        print map[keys]" -> "keys
}' file
failure -> usage
strton -> failure
main -> strton
main -> settimeout
main -> printackermann
main -> printfibupto
main -> failure
+2

sed , grep .. (, , , / ), .

#!/bin/bash

symbol='[_A-Za-z][_@A-Za-z0-9]\+'

objdump -d "$1" | sed -n "
/^[0-9a-f]\+ <\(${symbol}\)>:/{ # Match symbol in header
    s//\1/                      # Symbol only in pattern space
    h                           # Save symbol to hold space
    : loop                      # (until empty line)
    n                           # Next line
    /^$/!{                      # If not an empty line
        # Try matching 'callq' line and extract symbol:
        /^[:[:space:][:xdigit:]]\+callq[^<]\+<\($symbol\)>/{
            s//\1/              # Symbol only in pattern space
            G                   # Append hold space to pattern space
            # Swap words in pattern space, adding separator:
            s/\($symbol\)[[:space:]]\($symbol\)/\2 -> \1/g
            p                   # Print pattern space:
        }
        b loop                  # Try next line
    }
}"
+2

, bash :

#!/bin/bash
while read line
do
    [[ "$line" =~ \<(.*)\>\:$ ]] && caller=${BASH_REMATCH[1]}
    [[ "$line" =~ \<(.*)\>$ ]] && callee=${BASH_REMATCH[1]}
    [ -n $caller -a -n $callee ] && echo "$caller -> $callee";
    callee=""
done < $1

[[ expr ]] && test expr, true, . =~ , () ${BASH_REMATCH[1]}.

+1

Source: https://habr.com/ru/post/1532554/


All Articles