3

Here is my code

michal@argon:~$ cat test.txt 
1
  2
    3
      4
        5
michal@argon:~$ cat test.txt | while read line;do echo $line;done > new.txt
michal@argon:~$ cat new.txt
1
2
3
4
5

I don't know why the command echo $line filtered the space character, I want test.txt and new.txt to be exactly the same.

Please help, thanks.

wukong
  • 2,430
  • 2
  • 26
  • 33
  • See [this previous answer](http://stackoverflow.com/questions/1648055/preserving-leading-white-space-while-readingwriting-a-file-line-by-line-in-bas/1652684#1652684) – Gordon Davisson May 22 '13 at 22:29
  • You didn't chose a good example :) It looks like re-inventing the `cp` command :) – php-dev Jun 12 '15 at 09:03

3 Answers3

6

Several issues with your code.

  1. $parameter outside of " ". Don't.
  2. read uses $IFS to split input line into words, you have to disable this.
  3. UUOC

To summarize:

 while IFS= read line ; do echo "$line" ; done < test.txt > new.txt
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
2

While the provided answers solves your task at hand, they do not explain why bash and echo "forgot" to print the spaces you have in your string. Lets first make an small example to show the problem. I simply run the commands in my shell, no real script needed for this one:

mogul@linuxine:~$ echo      something
something
mogul@linuxine:~$ echo something
something

Two echo commands that both print something right at the beginning of the line, even if the first one had plenty space between echo and something. And now with quoting:

mogul@linuxine:~$ echo "     something"
     something

Notice, here echo printed the leading spaces before something

If we stuff the string into a variable it work exactly the same:

mogul@linuxine:~$ str="     something"
mogul@linuxine:~$ echo $str
something
mogul@linuxine:~$ echo "$str"
     something

Why?

Because the shell, bash in your case, removes space between arguments to commands before passing them on to the sub process. By quoting the strings we tell bash that we mean this literally and it should not mess with out strings.

This knowledge will become quite valuable if you are going to handle files with funny names, like "this is a file with blanks in its name.txt"

mogul
  • 4,441
  • 1
  • 18
  • 22
1

Try this --

$ oldIFS="$IFS"; IFS=""; while read line;do echo $line >> new.txt ;done < test.txt; IFS="$oldIFS"

$ cat new.txt
1
  2
      3
            4
                    5
Bill
  • 5,263
  • 6
  • 35
  • 50
  • 1
    You can run `IFS= read line` rather than change `IFS` globally. Your code fails to restore `IFS` in the (extremely unlikely) case that it was unset before. – chepner May 22 '13 at 20:30