batmancn batmancn - 27 days ago 8
Bash Question

How to process space at the head of line in file under shell?

I have a shell script to process old_file into new_file, I want to rewrite one line in old_file like this:

old_file:

123
abc
e45

new_file:

123
abc bca
e45


So I use codes like this:

cat old_file | while read line; do process "$line" > new_file; done


The process is a function to match and rewrite the line. But I found the space in the head of line in old_file is missing like this:

new_file:

123
abc bca
e45


So I change code into this:

echo "`cat old_file`" | while read line; do echo "$line" > new_file; done


But the lines in old_file will be one line(as "" works, sometimes this will got "File name too long" error), I want to process lines one by one, not whole lines together.

So how to process lines in old_file one by one, and at the same time, keep space in the head of line?

Thank you~

Answer Source

Given your edit, there are several issues. First, you are using the wrong tool for the job. If you want to change the line ' abc' to ' abc bca', then sed is the correct tool. For example, given old_file,

$ cat old_file
123
  abc
e45

You can accomplish what you want with a simple

$ sed 's/^\s*abc$/& bca/' old_file
123
  abc bca
e45

To edit the file in place, just add sed -i.bak to change the file in place while saving old_file.bak containing the original. (you can omit .bak and skip creating the backup)

Next, your command cat old_file is an Unnecessary Use Of cat (a UUOc). Simply redirect the file to your loop, e.g.

while read -r line; do echo "$line"; done <old_file

note: read skips leading whitespace. To preserve, if your shell (e.g. bash, etc.) provides an Internal Field Separator for word-splitting, setting IFS= will preserve leading whitespace, e.g.

while IFS= read -r line; do echo "$line"; done <old_file

Otherwise, check the options of your read implementation.

Next, after you process "$line" to add the ' bca' you can simply redirect all output to new_file. Running the while loop in a subshell allows you to redirect the entire output to new_file, e.g.

(while IFS= read -r line; do process "$line"; done <old_file) >new_file

Let me know if you have any further questions.