19

I've been googling this question to no avail. I'm automating a build process here at work, and all I'm trying to do is get version numbers and a tiny description of the build which may be multi-line. The system this runs on is OSX 10.6.8.

I've seen everything from using CAT to processing each line as necessary. I can't figure out what I should use and why.

Attempts

read -d '' versionNotes

Results in garbled input if the user has to use the backspace key. Also there's no good way to terminate the input as ^D doesn't terminate and ^C just exits the process.

read -d 'END' versionNotes

Works... but still garbles the input if the backspace key is needed.

while read versionNotes
do
  echo "  $versionNotes" >> "source/application.yml"
done

Doesn't properly end the input (because I'm too late to look up matching against an empty string).

  • You're getting this information from the user, correct? – glenn jackman Apr 9 '12 at 23:14
  • Correct; I want the user to enter this information in the terminal when executing the script. – Robert K Apr 10 '12 at 11:22
  • 1
    You haven't made yourself clear, I'd rather say. – poige Jun 11 '12 at 10:33
13

man bash mentions «…

The command substitution $(cat file) can be replaced by the equivalent but faster $(< file).

…»

$ myVar=$(</dev/stdin)
hello
this is test
$ echo $myVar
hello this is test
$ echo "$myVar"
hello
this is test

and I agree this is worth mentioning — echo "$myVar" would have displayed the input as it was given.

  • 1
    How to stop after multiline input? If I press Ctrl C it stops but the variable is not saved! – Nikhil Aug 13 '18 at 9:46
  • 1
    UNIX® terminals do have "discipline": en.wikipedia.org/wiki/Line_discipline • Check it out what does "eof" mean • Do read man stty, find out how to get current settings – poige Aug 13 '18 at 15:43
  • ctrl-d to stop. – freb Oct 23 '18 at 2:52
6

Refer to the excellent Bash Guide for all your bash scripting needs.

In particular the Bash FAQ contains this at number #1:

How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?

  • You say to use read -r, but how do I get it to do so from STDIN? I did attempt to use read -r early on. – Robert K Apr 25 '12 at 17:17
  • It reads from stdin by default. – adaptr Apr 26 '12 at 7:17
6

Try this:

user@host:~$ read -d '' x <<EOF
> mic
> check
> one
> two
> EOF

Without line breaks:

user@host:~$ echo $x
mic check one two

With line breaks:

user@host:~$ echo "$x"
mic
check
one
two
  • 2
    -d '' is exactly what I needed. Thanks – Bruno Bronosky Mar 9 '17 at 22:53
  • @Bruno My pleasure; it's a tricky one. Especially at first glance, it looks fairly standard. Can be quite useful though, once you get the hang of the various idiosyncrasies. – tjt263 Mar 11 '17 at 8:57
2

I've solved this issue by dealing with each line until I came up with a blank line. It works well enough for my situation. But if someone wants to add a better solution, feel free to do so.

echo "---
notes: |" > 'version.yml'

while read line
do
  # break if the line is empty
  [ -z "$line" ] && break
  echo "  $line" >> "source/application.yml"
done
  • Use read -r instead. – adaptr Apr 25 '12 at 13:26
1

You can start an editor like vim, pico...

${VISUAL:-${EDITOR:-vi}} source/application.yml
  • Um... how does that answer the OP's question in any way ? – adaptr Apr 25 '12 at 13:27
  • He can start the editor from the script. – Mircea Vutcovici Apr 25 '12 at 14:46
  • And that accomplishes what, exactly ? He wants to use text from a file in the script, not write information to a file. – adaptr Apr 25 '12 at 15:05
  • He wasnts to read text from the user and write it to a file. Please read the comments added to the question. – Mircea Vutcovici Apr 25 '12 at 16:03
1

First a few corrections:

  1. To allow "edition" on the line use -e which uses readline (so you have the bash history and all editing features)
  2. -d only takes one character. E.g. from 'END' takes 'E' and whenever the user writes an 'E' the reading stops (I guess that's not what you want...)

There are a few possibilities to do this. I'd go for read line by line and stop when an empty line is found (though you could set any stop word):

unset tmp
while :
do 
 read line
 [[ $line == "" ]] && tmp="${tmp:0:$((${#tmp}-1))}" && break
 tmp="$tmp"$line$'\n'
done
0

We are using a construct using xargs and ctrl-d for breaking. I'm not perfectly satisfied with it, but it certainly does the job of taking multi-line user input and stuffing that into a file (formatting intact).

printf "Give me some input!  Use ctrl-d when you are done.  \n"
touch /some/path/file.txt
`xargs -0 > /tmp/.reminder/file.txt`
0

You have several methods.

One of the simplest methods is:

MYVAR=$(yourcommand)
echo $"MYVAR"

For example:

MYVAR=$(ls /)
echo $"MYVAR"
  • Except I'm not executing a shell command like LS. I'm requesting multi-line input from the user. – Robert K Apr 10 '12 at 11:23
  • This is very bad practice; do not process the output of ls! – adaptr Apr 25 '12 at 13:14
  • @adaptr We've heard it all before, would you mind suggesting a good alternative, please? – tjt263 Mar 11 '17 at 8:50
-1

See: http://tldp.org/LDP/abs/html/internal.html#READR

Use read and note that if you end a line with \ the newline is ignored. So you could do:

#!/bin/bash

read -p "version: " version
echo $version

# enter some input and end long lines with "\", then plain enter at the end
read -p "description: " description
echo -e "$version\n$description >> yourfile.txt
  • If I just wanted a paragraph with line breaks ignored, yes. But as this is a generated list of release notes for a build script, I need to be able to preserve those line breaks; I might try to enter a bulleted list, for example. – Robert K Apr 25 '12 at 13:09
  • The ABS is a monstrosity of horrific proportions. 90% of it is plain wrong. – adaptr Apr 25 '12 at 13:26
  • It's not that bad. – tjt263 Mar 11 '17 at 8:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.