2

any help on this problem is appreciated I have a text file with the following format

We can safely assume that the names are always three characters long, profession 7 characters and salary 5 characters The varaibles come from user input and not as a parameters.

BobJanitor20000
TedBuilder30000
NedFighter25000
KitTeacher40000

I ask the user for a name input and another input whether to display occupation or Salary

If the user enters "Ted" and chooses salary, the output should be

Ted 30000

The program must also take into account partial name matches, "ed" and salary should output

Ted 30000
Ned 25000

I know cut and grep can get me the relavent lines but how do I create the output I want?

3
  • 1
    Are the name always 3 characters long? And can the script accept the values as parameters: /blah/script Ted salary or must they be read by the stdin?
    – chaos
    Commented Oct 20, 2015 at 9:46
  • yes, assume that the names are always three characters long, profession 7 characters and salary 5 characters: varaibles come from user input and not as a parameters. Commented Oct 20, 2015 at 9:55
  • can't use awk, sed or any other string utilities, updated OP Commented Oct 20, 2015 at 9:55

7 Answers 7

4
$ grep -F ed file|fold -w 5|fold -w 3|grep -E '^[[:upper:]]..|^[0-9]'|paste -sd ' \0\n' -
Ted 30000
Ned 25000

Or:

$ cut -c 1-3,11- file | grep -F ed | fold -w 3 | paste -sd ' \0\n' -
Ted 30000
Ned 25000

Or (assuming GNU grep):

$ grep -oE '^.{3}|.{5}$' file | paste -sd ' \n' - | grep -F ed
Ted 30000
Ned 25000

You could also do (assuming a shell with process-substitution support) something like:

separate() {
  fold -w 1 -- "$@" |
    paste -sd '\0\0 \0\0\0\0\0\0 \0\0\0\0\n' - |
    sort -k 1,1
}

join <(separate file | cut -d ' ' -f 1 | grep -F ed
      ) <(separate file) | cut -d ' ' -f 1,3
2
  • 1
    cut -c4-10 --complement file
    – Costas
    Commented Oct 20, 2015 at 12:02
  • 1
    @Costas, only with GNU cut. That would be sacrificing portability to cosmetic. Commented Oct 20, 2015 at 14:13
3

Here is a script that works for a name search. I'm using a here document (aka heredoc) instead of an external file to deliver the list to the while loop so that it's all contained in this file for ease of reading. You can expand it as you wish.

Read man bash for information on builtin commands, (and search the manual for things I have made bold) I'm using,

  • Substring Expansion to get the parts of the line
  • Regular Expression matching to find the match =~
  • [[...]] to return a conditional value (0 or 1) depending on internal expression

Heres the script:

read -p "Input Name: " SearchName
while read line 
do
  Name=${line:0:3}
  Job=${line:3:7}
  Salary=${line:10:5}
  [[ $Name =~ $SearchName ]] && echo $Name $Salary
done << "end--"
BobJanitor20000
TedBuilder30000
NedFighter25000
end--

user@machine:~/tmp$ bash manipvar.sh 
Input Name: ed
Ted 30000
Ned 25000
user@machine:~/tmp$ 
2

Assuming separation is based on capital letter.

with SED

name + salary

sed -e "/${NamePart}.*[A-Z].*/ !d" -e 's/\([A-Z][a-z]*\)[A-Z][a-z]*\([0-9]*\)/\1 \2/' YourData.file

name + occupation

sed -e "/${NamePart}.*[A-Z].*/ !d" -e 's/\([A-Z][a-z]*\)\([A-Z][a-z]*\)[0-9]*/\1 \2/' YourData.file
4
  • hello, not allowed to use sed, awk or any other string utilities. And separation is based on predetermined length like name being 3 characters, profession being 6 and salary being 5 Commented Oct 20, 2015 at 9:58
  • Is this some type of homework? In that case, I suppose it has a solution. I think the easiest way is using awk, sed or cut but if you can't use these tools...
    – migrc
    Commented Oct 20, 2015 at 10:31
  • you can use cut, just not awk or sed. And yes it is homework Commented Oct 20, 2015 at 10:34
  • take a look at this stackoverflow.com/questions/1405611/…
    – migrc
    Commented Oct 20, 2015 at 11:01
1

Use this (pure bash) script:

#!/bin/bash

# make the search case insensitive
shopt -s nocasematch
unset a; declare -A a

# read the name and save it in $name
read -p "Enter the Name: " name

# read the salary or profession and save it in $type
select type in salary profession;
do
  # loop trough the file
  while read l; do
    # characters 0 to 3 are the name
    n=${l:0:3}
    # the profession and the salary
    a["profession"]="${l:3:7}"
    a["salary"]="${l:10:5}"
    # if the name matches print the selected type
    [[ $n =~ $name ]] && echo "$n ${a[$type]}"
  done <file # the input file
  exit
done

The output:

$ ./script
Enter the Name: ed
1) salary
2) profession
#? 1
Ted 30000
Ned 25000
$ ./script
Enter the Name: ted
1) salary
2) profession
#? 2
Ted Builder
$ ./script
Enter the Name:
1) salary
2) profession
#? 2
Bob Janitor
Ted Builder
Ned Fighter
Kit Teacher
0

This one worked for me

$ echo `grep -oe '^...\|[0-9]\{5\}' filename` | grep -oe '.\{9,10\}$\?' | grep ed
Ted 30000 
Ned 25000
0

Here's one that works kinda backwards:

xargs -I{} -n1      \
    expr {}\ {} : '[^0-9]*\(.* .ed\).*'

expr is handed two copies of each line back-to-back and divided by a space as its first argument. Like:

expr 'TedBuilder20000 TedBuilder20000' : '[^0-9]*\(.* .ed\).*'

And so its matched returns - if any - are Salary then Name:

printf %s\\n BobJanitor20000 TedBuilder30000 \
             NedFighter25000 KitTeacher40000 |
xargs -I{} -n1      \
    expr {}\ {} : '[^0-9]*\(.* .ed\).*'

30000 Ted
25000 Ned

This works, though:

xargs sh -c <input  '
      for a do case $a in (?ed*) ! :; esac  ||
            printf  %-4.3s${a##*[!0-9]}\\n "$a"
      done' '' 

Ted 30000
Ned 25000
0

For fun, here is a POSIX solution using neither grep nor cut :

#!/bin/sh -

while IFS= read -r line; do
    name=${line%[A-Z]*} # remove smallest suffix beginning with uppercase
    occ=${line#???} # remove first 3 characters
    occ=${occ%?????} # remove last 5 characters
    salary=${line##*[!0-9]} # remove largest prefix ending with a non-digit
    case $name in
        *$1*)
            if [ "$2" = occupation ]; then
                printf '%s %s\n' "$curr_name" "$curr_occ"
            else
                printf '%s %s\n' "$curr_name" "$curr_salary"
            fi
    esac
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .