Echo Output on the Same line [duplicate]
I am trying get a output printed on a same line using echo command in bash script. Echo Command is given inside a loop, everytime the loop runs, executes a echo command. But normally, echo will take a new line everytime it executes, but I want the output to be on the same line everytime it executes. This is how my sample small code look:
#!/bin/bash loop=1; while [ $loop -lt 5 ]; do echo "-" let loop=loop+1 done
I also tried with -n option of echo command, but I got no output. I replaced the stmt — echo «-» with echo -n «-«. Desired output is: «——» Can some one help me on this
I am beginner to shell. ‘Powershell’ also appeared as a suggestions to the tags. I don really know the difference between the shell and powershell.
You can always hover over the tags and it will give you a description. I removed the tag and added bash so the right people will find your question.
3 Answers 3
which should have worked. In fact, I suspect that it did.
The problem may be that you don’t have a newline at the very end of your output. With the change to
your script should print 5 — characters with no newline. The output may have been clobbered by the shell prompt printed after your script finishes.
As a quick test, try adding
to the end of your script and see if the —— appears. After 5 seconds, see what happens when your next shell prompt is printed.
#!/bin/bash loop=1; while [ $loop -lt 5 ] do echo -n "-" let loop=loop+1 done echo ""
The final echo «» prints just a newline.
Some other things to note:
Indentation is important, especially for larger and more complex scripts. It shows the structure of your code at a glance and makes it much easier to read.
In the code in your question, you have a space in front of the #!/bin/bash . The #! is recognized only at the very beginning of the line. Without a valid #! line, your script will be executed by /bin/sh , not by /bin/bash . It probably doesn’t matter in this case, since you’re not using any bash-specific features. It may have been an error introduced when you posted the question, but be sure to check your actual script and remove the space if it’s there.
The echo command exists in a number of different versions. It’s built into most shells, and also available as a separate executable /bin/echo . The different versions can have subtly different behavior in which options they recognize and the syntax of special characters. Support for the -n option to print a line with no terminating newline is probably almost universal.
The printf command (similar to C’s printf() function) also exists in multiple implementations, but its behavior is much more consistent. It’s safer to use printf rather than echo if you’re doing anything more than printing a simple one-line message. Again, it probably won’t matter in this case, but it’s a good thing to keep in mind.
How to print out to the same line, overriding previous line?
Sometimes I see some commands in the terminal that print results to stdout but in the same line. For example wget prints an arrow like below:
0[=> ]100% 0[ => ]100% 0[ => ]100% 0[ => ]100% 0[ =>]100%
but it is printed out to the same line so it looks like the arrow is moving. How can I achieve the same thing in my programs using bash or sh? Do I need to use other tools? UPDATE: I know I mentioned wget, which comes by default in linux, GNU based unices . Is there a general approach that works on BSDs too? (like OSX) -> OK, If I use bash instead of sh then it works 🙂
3 Answers 3
Use the special character \r . It returns to the beginning of the line without going to the next one.
for i in ; do echo -n '[' for ((j=0; j' for ((j=i; j
You can use \r for this purpose:
For example this will keep updating the current time in the same line:
while true; do echo -ne "$(date)\r"; done
You can also use ANSI/VT100 terminal escape sequences to achieve this.
Here is a short example. Of course you can combine the printf statements to one.
#!/bin/bash MAX=60 ARR=( $(eval echo >) ) for i in $ ; do # delete from the current position to the start of the line printf "\e[2K" # print '[' and place '=>' at the $i'th column printf "[\e[%uC=>" $ # place trailing ']' at the ($MAX+1-$i)'th column printf "\e[%uC]" $(($+1-$)) # print trailing '100%' and move the cursor one row up printf " 100%% \e[1A\n" sleep 0.1 done printf "\n"
With escape sequences you have the most control over your terminal screen.
You can find an overview of possible sequences at [1].
How to concatenate multiple lines of output to one line?
If I run the command cat file | grep pattern , I get many lines of output. How do you concatenate all lines into one line, effectively replacing each "\n" with "\" " (end with " followed by space)? cat file | grep pattern | xargs sed s/\n/ /g isn't working for me.
By the way: (1) you need to put your sed script in single-quotes so that Bash doesn't mess with it (since sed s/\n/ /g calls sed with two arguments, namely s/n/ and /g ); (2) since you want the output of cat file | grep pattern to be the input to sed , not the arguments to sed , you need to eliminate xargs ; and (3) there's no need for cat here, since grep can take a filename as its second argument. So, you should have tried grep pattern file | sed 's/\n/ /g' . (In this case it wouldn't have worked, for reasons given at the above link, but now you know for the future.)
Question with 68 votes (140k views) duplicated with post which has only 1 vote (12k views)? This isn't right.
12 Answers 12
Use tr '\n' ' ' to translate all newline characters to spaces:
Note: grep reads files, cat concatenates files. Don't cat file | grep !
tr can only handle single character translations. You could use awk to change the output record separator like:
$ grep pattern file | awk '' ORS='" '
This works out nicely, however I don't want the separator to show up on the very last entry. Example, per your " , it shows up like one" two" three" , however I'd want it to show up like one" two" three . Note the last three doesn't have a parenthesis. Any ideas?
@oink you could pipe the results into sed '$s/..$//' to delete the last 2 characters on the last line.
If you want to replace newlines with nothing, you need to use the --delete option as the default expects two arguments. e.g. tr --delete '\n' .
Piping output to xargs will concatenate each line of output to a single line with spaces:
Or any command, eg. ls | xargs . The default limit of xargs output is ~4096 characters, but can be increased with eg. xargs -s 8192 .
| tr '\n' ' ' was not working for me when called through php exec function. It was ignoring tr, and just giving last match from grep. | xargs worked.
In bash echo without quotes remove carriage returns, tabs and multiple spaces
Severely underrated answer here, this is really simple and works like a charm, with a trailing newline as well.
Or just echo $( Works very nicely on Unix systems - but Windows (eg. MSYS2 / Git Bash) doesn't behave the same way - could be other systems that don't work the same way as well. awk works most reliably for me cross-platform. This could be what you want As to your edit, I'm not sure what it means, perhaps this? (this assumes that ~ does not occur in file ) @Stephan there was no need to assume that cat file will actually be cat , or even a file. (I just left that part unchanged as it was irrelevant to the question) This is an example which produces output separated by commas. You can replace the comma by whatever separator you need. When we want to replace the new line character \n with the space: xargs has own limits on the number of characters per line and the number of all characters combined, but we can increase them. Details can be found by running this command: xargs --show-limits and of course in the manual: man xargs When we want to replace one character with another exactly one character: When we want to replace one character with many characters: First, we replace the newline characters \n for tildes ~ (or choose another unique character not present in the text), and then we replace the tilde characters with any other characters ( many_characters ) and we do it for each tilde (flag g ). Here is another simple method using awk : Also, if your file has columns, this gives an easy way to concatenate only certain columns: I like the xargs solution, but if it's important to not collapse spaces, then one might instead do: That will replace newlines for spaces, without substituting the last line terminator like tr '\n' ' ' would. This also allows you to use other joining strings besides a space, like a comma, etc, something that xargs cannot do: Here is the method using ex editor (part of Vim):cat file | grep pattern | paste -sd' '
cat file | grep pattern | paste -sd'~' | sed -e 's/~/" "/g'
The fastest and easiest ways I know to solve this problem:
# cat > file.txt a b c # cat file.txt | awk '< printf("%s ", $0) >' a b c
# cat > cols.txt a b c d e f # cat cols.txt | awk '< printf("%s ", $2) >' b e
$ seq 1 5 | sed ':b;N;$!bb;s/\n/,/g' 1,2,3,4,5
Join all lines and print to the standard output:
Probably the best way to do it is using 'awk' tool which will generate output into one line
$ awk ' /pattern/ ' ORS=' ' /path/to/file
It will merge all lines into one with space delimiter
You don't need
Here's what worked for me on mac using bash
cat file | grep pattern | paste -d' ' -s -
-d list Use one or more of the provided characters to replace the newline characters instead of the default tab. The characters in list are used circularly, i.e., when list is exhausted the first character from list is reused. This continues until a line from the last input file (in default operation) or the last line in each file (using the -s option) is displayed, at which time paste begins selecting characters from the beginning of list again. The following special characters can also be used in list: \n newline character \t tab character \\ backslash character \0 Empty string (not a null character). Any other character preceded by a backslash is equivalent to the character itself. -s Concatenate all of the lines of each separate input file in command line order. The newline character of every line except the last line in each input file is replaced with the tab character, unless otherwise specified by the -d option. If ‘-’ is specified for one or more of the input files, the standard input is used; standard input is read one line at a time,
circularly, for each instance of ‘-’.