LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Bash: prevent read to remove spaces (https://www.linuxquestions.org/questions/linux-newbie-8/bash-prevent-read-to-remove-spaces-4175438626/)

killout 11-25-2012 07:18 AM

Bash: prevent read to remove spaces
 
Hello, linuxquestions.

I have reading "Unix and Linux adminitration handbook", and faced with a problem:

I have command:
Code:

alex@just ~ $ echo one two; echo three          four  |  while read -e "fname"; do echo ${fname} ; done
one two
three four

Why the is only one space betweeen "three" and "four" in the output? How can i prevent this?

pixellany 11-25-2012 07:54 AM

Here's a hint:
Code:

[mherring@herring_lap play]$ echo $var
three four
[mherring@herring_lap play]$ echo "$var"
three    four


shivaa 11-25-2012 08:12 AM

You can print multiple space(s) using \n or tab(s) using \t, as:
Code:

echo -e "three\nfour"  # For one space
echo -e "three\n\nfour"  # For two spaces
echo -e "three\tfour"  # For one tab space
echo -e "three\t\tfour"  # For two tab space and so on...

Output:
Code:

three four
three  four
three    four
three          four


killout 11-25-2012 09:08 AM

Quote:

Originally Posted by shivaa (Post 4836537)
You can print multiple space(s) using \n or tab(s) using \t, as:
Code:

echo -e "three\nfour"  # For one space
echo -e "three\n\nfour"  # For two spaces
echo -e "three\tfour"  # For one tab space
echo -e "three\t\tfour"  # For two tab space and so on...

Output:
Code:

three four
three  four
three    four
three          four


Shivaa, thank you for your advice, but i can't apply it because task is rename files with using "find", pipe it to "while read fname" commands.

killout 11-25-2012 09:09 AM

Quote:

Originally Posted by pixellany (Post 4836526)
Here's a hint:
Code:

[mherring@herring_lap play]$ echo $var
three four
[mherring@herring_lap play]$ echo "$var"
three    four


pixellany, thank you! Your ancwer helps me:

Code:

alex@just ~ $ echo "one two"; echo "three          four"  |  while read fname; do echo "$fname" ; done
one two
three          four


David the H. 11-25-2012 10:13 AM

It's vital in scripting to understand how the shell handles arguments and whitespace. Study these links for the details:

http://mywiki.wooledge.org/Arguments
http://mywiki.wooledge.org/WordSplitting
http://mywiki.wooledge.org/Quotes

The function of the echo command is to print each and every argument it gets separately, with a single space between them. Since your text strings are unquoted the shell breaks the them up into their individual words before echo processes them.

Next, if we look closely at your original scriptlet:

Code:

$ echo one two; echo three          four  |  while read -e "fname"; do echo ${fname} ; done
one two
three four

The semicolon between the two echos means you are running two separate commands. The first echo executes and prints "one two" to stdout, then the second echo executes, sending its output into the while loop, which prints it with the third echo. So only "three four" is actually processed by the loop. This can be avoided with command grouping, or through the use of "echo -e" to combine them into a single command, as pointed out by shivaa.


Next, you should be aware of the variable scoping limitation when using pipes. The above will work as long as you are only echoing the results, but it wouldn't work if you needed to set variables that are still needed after the loop terminates.

The recommended bash syntax is to instead feed the loop with a process substitution or a here doc/here string.

Code:

while read -r fname; do
        echo "$fname"
done < <( echo -e 'one two\nthree          four' )

while read -r fname; do
        echo "$fname"
done <<<$'one two\nthree          four'

As mentioned in the quoting page I gave above, the special $'..' quoting pattern acts similarly to echo -e, expanding backslash characters.

The -e option to read is also superfluous if you aren't using it interactively, BTW. But it is recommended to always use the -r option, particularly if the input text can contain literal backslashes.


Finally, be aware that printf is often a better choice when you simply need to output your data on multiple lines, since it has implicit looping built into it.

Code:

printf '%s\n' 'one two' 'three          four'

killout 11-29-2012 02:03 PM

David the H., thanks for such a detailed response!
I will study links,that you have posted.

David the H. 11-30-2012 05:46 AM

Glad to help out.

I should probably also have included BashFAQ #1, which is all about how to properly read lines of text input.

When you get a chance, also take the time to read through the whole BashGuide from the same site. It provides an excellent overview of all the basics you should know for good scripting. Then round it off with the BashPitfalls, to help you avoid common errors.


All times are GMT -5. The time now is 04:01 AM.