1

I have a file with this structure:

picture1_123.txt
picture2_456.txt
picture3_789.txt
picture4_012.txt

I wanted to get only the first segment of the file name, that is, picture1 to picture4. I first used the following code:

cat picture | while read -r line; do cut -f1 -d "_"; echo $line; done

This returns the following output:

picture2
picture3
picture4
picture1_123.txt

This error got corrected when I changed the code to the following:

cat picture | while read line; do s=$(echo $line | cut -f1 -d "_"); echo $s; done

picture1
picture2
picture3
picture4

Why in the first:

  1. The lines are printed in a different order than the original file?
  2. no operation is done on picture1_123.txt and picture1 is not printed?

Thank you!

3
  • Your cut command is reading the entire rest of stdin, so nothing is left for the next read command. Commented Oct 26, 2020 at 15:43
  • ...if you wanted it to cut contents in line only, and save the result back to line, that might instead be line=$(cut -f1 -d "_" <<<"$line") -- but don't do that, starting a new copy of cut per line of input is horribly inefficient. Commented Oct 26, 2020 at 15:44
  • Also, note that echo $line is itself buggy. Always, always quote your expansions, as in echo "$line"; see I just assigned a variable, but echo $variable prints something else! -- or try testing with a file named *_foo.txt Commented Oct 26, 2020 at 15:48

1 Answer 1

2

What Was Wrong

Here's what your old code did:

  • On the first (and only) iteration of the loop, read line read the first line into line.
  • The cut command read the entire rest of the file, and wrote the results of extracting only the desired field to stdout. It did not inspect, read, or modify the line variable.
  • Finally, your echo $line wrote the first line in entirety, with nothing being cut.
  • Because all input had been consumed by cut, nothing remained for the next read line to consume, so the loop never ran a second time.

How To Do It Right

The simple way to do this is to let read separate out your prefix:

while IFS=_ read -r prefix suffix; do
  echo "$prefix"
done <picture

...or to just run nothing but cut, and not use any while read loop at all:

cut -f1 -d_ <picture
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.