3
    size=$(wc -l < "$1")
    if [ "$size" -gt 0 ]
    then
        tr "[:lower:]" "[:upper:]" < $1  > output
        for (( i=1; i <= "$size"; ++i ))
        do
            echo "Line " $i $(head -"$i" > output | tail -1 > output)
        done

Hi, guys! I have a problem with this little code. Everything works fine except the head-tail thing. What I wanna do is just displaying the line number "i" from a file. The results that I receive are just the last line ($size).

I think maybe it is something wrong with the input of tail. The head -"$i" doesn't go at the specified line. :( Any thoughts?

Ohhhh... I just realised: As input for my tail i give the same input for head. The solution is to give to tail the result from head. How do I do that? :-/

Marko
  • 407
  • 1
  • 7
  • 19
  • Look at the very first post: http://stackoverflow.com/questions/6022384/bash-tool-to-get-nth-line-from-a-file As long as it works for the last line, it must work for every line. The speed of execution is not influencing me, i have small files. So I dont wanna use sed. – Marko Mar 21 '16 at 19:16

4 Answers4

1

You don't need to redirect to file output from head. Otherwise, the pipe does not get any input at all. Also, use >> to append results otherwise you will just keep overwriting the file with the next iteration of the loop. But make sure to delete the output file before each new call to the script, else you will just keep appending to the output file infinitely.

echo "Line " $i $(head -"$i" $infile | tail -1 >> output)
Munir
  • 3,442
  • 3
  • 19
  • 29
  • What exactly will do >> in this case, please? – Marko Mar 21 '16 at 19:28
  • `>>` is used to append output to file. So, if the file already exists, it will add a new line to that file with whatever is returned without erasing the existing content. `>` will erase the contents of the file if it exists, and then add the new lines. So, if you use `>` in a loop, you only get the output from the last iteration. To prevent that, use `>>`. – Munir Mar 21 '16 at 19:34
  • Ohh..thats why I was getting just the last line. I got it. Thank you! – Marko Mar 21 '16 at 19:36
  • But still, what file does head manipulates? From what i know the structure is like this: head -n in_file. Isnt it? – Marko Mar 21 '16 at 19:39
  • Yes, you need to provide that from your code. I would create a variable called infile like `infile=$1` at the very start of the script and then pass it to head with `head -"$i" $infile`. See edit. – Munir Mar 21 '16 at 19:43
1

Use read to fetch a line of input from the file.

# Since `1` is always true, essentially count up forever
for ((i=1; 1; ++i)); do
    # break when a read fails to read a line
    IFS= read -r line || break
    echo "Line $i: $(tr [:lower:] [:upper:])"
done < "$1" > output

A more standard approach is to iterate over the file and maintain i explicitly.

i=1
while IFS= read -r line; do
    echo "Line $i: $(tr [:lower:] [:upper:])"
    ((i++))
done < "$1" > output
chepner
  • 497,756
  • 71
  • 530
  • 681
0

I think you're re-implementing cat -n with prefix "Line ". If so, awk to the rescue!

awk '{print "Line "NR, tolower($0)}'
karakfa
  • 66,216
  • 7
  • 41
  • 56
  • awk finds and replaces text, I just echo the number of the line ($i) and I try to echo the line itself also, but works just for the last line. I wanna repair the pipe thing not using another command. – Marko Mar 21 '16 at 19:18
  • Ohhhh... I just realised: As input for my tail i give the same input for head. The solution is to give to tail the result from head. How do I do that? :-/ – Marko Mar 21 '16 at 19:23
  • `awk` doesn't replace any text, it takes input and produces output. Your pipe command is broken because that's not what pipe is for. You want to remove `> output` from the first part where head is. – karakfa Mar 21 '16 at 19:23
  • If I remove the first output, how will head know from which file to colect info, please? – Marko Mar 21 '16 at 19:27
  • 1
    you have to provide the file name which is the input, "$1" your case. But, you're making it harder than necessary. It should be something like `head -$i $1 | ... `. Did you try the script I proposed? – karakfa Mar 21 '16 at 19:32
  • I know it will work, but the satisfaction of repairing and using your own is biger, u know that. :) But I really apreciate your sugesstion! – Marko Mar 21 '16 at 19:34
  • Also, you have to move `tr` down there and pipe in to head if you want to lowercase as well, so it should be `tr ... | head -$i | tail ...` If you're on the wrong track fixing it not the best course of action. You are not using the tools at your disposal properly. Good luck. – karakfa Mar 21 '16 at 19:35
  • Dont mind the other code. TR is at good place. I wanna just understand this line: $(head -"$i" < output > outputF | tail -1 < outputF). It works, but I see that it is too much effort. – Marko Mar 21 '16 at 19:43
0

I made it. :D

The trick is to put the output of the head to another file that will be the input for tail, like that:

echo "Line " $i $(head -"$i" < output >outputF | tail -1 < outputF)

Your questions made me think differently. Thank you!

Martin Tournoij
  • 26,737
  • 24
  • 105
  • 146
Marko
  • 407
  • 1
  • 7
  • 19