bash,使用here文档,如何读取用户输入的多行内容,在空行中停止

时间:2021-04-27 15:42:58

Is there a way that I can make a heredoc in a script interactive as if I am at the prompt?

是否有一种方法可以让赫里多克在脚本中进行交互,就像我在提示符处一样?

This is over ssh from linux to an ssh server runing on android connecting through mosh.

这是通过从linux到运行在android上的ssh服务器,通过mosh连接。

I'm making a set of a few small scripts to allow me to reasonably sms over ssh on my android from my laptop using bash under the app termux.

我正在编写一组小脚本,让我可以在termux应用程序下使用bash在android上通过ssh发送短信。

While testing the send command at the prompt all works well:

在提示符下测试发送命令时,一切都运行良好:

termux-sms-send -n "$(tail -n1 number | tr -d ' ')" << ''

However, when inside a script this no longer works. This is the result:

但是,当在脚本内部时,它就不能工作了。这是由于:

./main.sh: line 34: warning: here-document at line 33 delimited by end-of-file (wanted `')
./main.sh: line 35: syntax error: unexpected end of file

I could of course do it another way but it's so neat and simple with the heredoc method and it's something I haven't really used before in bash and I am unsure how to get the read command to work nicely with multi line input in such a graceful way as this.

当然我可以做另一种方式但很整洁和简单heredoc方法,这是我在bash还没有使用过,我不知道怎么读命令来很好地处理多行输入在这样一个优雅的方式。

__

__

Edit Addition:

编辑补充:

In case anyone is interested and for context this is the script:

如果有人感兴趣,这是剧本:

searchTxt=""
contacts="$(termux-contact-list | jq -r '.[].name')"

clear 

while :; do
   echo -ne "\nEnter searchterm: $searchTxt"
   read -rsn1 ret; clear

   if [ ${#ret} -eq 0 ]; then
      if [ $(wc -l <<< "$choice") -gt 1 ]; then
         echo -en "type enough characters to narrow down selecton until only 1 remains\n\n"
      else
         echo "choice = $choice"
         number="$(termux-contact-list | jq -r ".[] | select(.name==\"$choice\") | .number")"
         echo "using number: $number"
         echo "$choice" > number
         echo "$number" >> number
         break
      fi
   fi

   searchTxt+=$ret
   choice=$(grep -i "$searchTxt" <<< "$contacts")
   echo "$choice"
done

while :; do
   clear 
   echo "Type message to send, enter a blank line to send message"
   echo -n "message: "

   termux-sms-send -n "$(tail -n1 number | tr -d ' ')" << ''
done

1 个解决方案

#1


2  

The proposed idiom is looking for a bare newline in the code (since the code is from where the heredoc is being read), as opposed to a bare newline in stdin.

所提议的习惯用法是在代码中寻找一个空的换行符(因为代码来自读取赫里多克文档的地方),而不是stdin中的空换行符。

That works at an interactive prompt, where your code is coming from stdin -- but the reason it doesn't work from a script should be obvious.

这在交互提示符(您的代码来自stdin)中起作用——但是它不能从脚本中工作的原因应该是显而易见的。

The following loop is explicit about looking in the input stream:

下面的循环是关于查看输入流的显式循环:

while IFS= read -r line; do
  [[ $line ]] || break
  printf '%s\n' "$line"
done | termux-sms-send -n "$(tail -n1 number | tr -d ' ')"

#1


2  

The proposed idiom is looking for a bare newline in the code (since the code is from where the heredoc is being read), as opposed to a bare newline in stdin.

所提议的习惯用法是在代码中寻找一个空的换行符(因为代码来自读取赫里多克文档的地方),而不是stdin中的空换行符。

That works at an interactive prompt, where your code is coming from stdin -- but the reason it doesn't work from a script should be obvious.

这在交互提示符(您的代码来自stdin)中起作用——但是它不能从脚本中工作的原因应该是显而易见的。

The following loop is explicit about looking in the input stream:

下面的循环是关于查看输入流的显式循环:

while IFS= read -r line; do
  [[ $line ]] || break
  printf '%s\n' "$line"
done | termux-sms-send -n "$(tail -n1 number | tr -d ' ')"