Bash:从终端交互式输入大型 html 块并将其保存到变量中

Bash:从终端交互式输入大型 html 块并将其保存到变量中

这很简单

#!/bin/bash
echo "What is your name?"
read name
echo "Your name is: $name"

但是,如果我不想处理名称,而是处理带有嵌套标签及其所有特殊字符的大型 HTML 代码块,该怎么办? (将交互式粘贴的块)

如何通过终端输入使用 bash 脚本将整个 html 代码块保存到变量中?

答案1

read您可以使用 直接从输入中读取内容,而不是使用 读取一行cat。这将从中读取标准输入(通常是终端,如果您直接在提示符下键入)并写入标准输出(也是终端)。使用 Ctrl/D 结束输入:

cat

在更一般的情况下,该cat命令从作为参数列出的另一个文件中读取,或者标准输入如果未指定,则将所有输入的内容写入标准输出

将其放入您的程序中,

#!/bin/bash
echo "What is your name?"
name=$(cat)
printf 'Your name is: "%s"\n' "$name"

在本例中,输出被发送到变量$name

答案2

你可以尝试类似的东西

read -r -d name <<-EOF

插入您的代码。您可以粘贴任意多行。EOF在一行中输入一个bare来结束输入。

答案3

由于您没有提到禁止临时文件,所以我使用文本编辑器有一个奇怪的解决方案:

# Variables
INPUT_TEXT=
TEMP_FILE=temp.html

# Set default editor for the system as nano unless defined
# Hard-code if you can, more consistent usage and users cannot invoke any program they desire through environment variable
EDITOR="${EDITOR:=nano}"

# WARNING: This line here might be a security issue, as it exposes use of a text editor freely, even if you hard-code the editor.
# Get input in a subshell (that's the key part here)
# The &3,&1,&2 redirections are beyond my grasp, but it is said it swaps stdout and stderr. The end goal here is to get TUI interaction with the subshelled command (likely nano in this script).
$( ${EDITOR} $TEMP_FILE 3>&1 1>&2 2>&1 );

# If above subshell ran successfully and user exitted saving the file
if [ $? = 0 ] && [ -f $TEMP_FILE ];
then
  INPUT_TEXT=$(cat $TEMP_FILE);

  # Remove temporary file, only when actually created
  rm $TEMP_FILE;
fi;

echo "$INPUT_TEXT"

以单行形式:

EDITOR=${EDITOR:=nano}; INPUT_TEXT=; TEMP_FILE=temp.txt; $($EDITOR $TEMP_FILE 3>&1 1>&2 2>&1); if [ $? = 0 ] && [ -f $TEMP_FILE ]; then INPUT_TEXT=$(cat $TEMP_FILE); rm $TEMP_FILE; fi; echo "$INPUT_TEXT"

编辑:如果您想专门使用 HTML,则能够使用语法突出显示相应地设置文件扩展名。

答案4

使用zsh而不是bash,您可以使用其vared变量编辑器,该编辑器使用 zsh 的行编辑器(zle)并允许在输入中嵌入换行符:

#! /bin/zsh -
text=
vared -p 'text: ' text
printf 'Got: <%s>\n' "$text"

要在文本中输入文字换行符,请输入+ AltEnter或者如果+已绑定到环境中的其他内容,则输入 + ,或者 输入+后跟+ ,(+发送又名换行符或字符,同时发送又名回车符或回车符)就像您在 zsh shell 提示符下一样。EscEnterAltEnterCtrlVCtrlJCtrlJ^J\nEnter^M\r

Enter单独提交文本。

您可以bindkey '^M' self-insert-unmeta在调用varedfor之前添加Enter来输入文字换行符,并让用户使用Ctrl+提交文本J(或将任何其他键或组合键绑定到accept-line)。

由于zle支持多个终端模拟器支持括号内的粘贴功能,并且默认启用它,您应该能够在那里粘贴多行文本。如果无法启用括号内的粘贴,则^M如上所述的重新绑定应该可以工作,因为终端仿真器在粘贴时通常会将\n' 转换为\r' 。

请注意,出于安全原因,终端仿真器不允许您粘贴许多控制字符,即使您将它们配置为允许它们,有些控制字符(如^C^Z也会被 tty 设备拦截以发送 SIGINT、SIGTSTP 信号。不过对于 HTML 文本来说应该不是问题。


bash必须read -e使用其行编辑器从用户那里读取文本。bash的行编辑器(readline)还可以让您使用Ctrl+V后跟Ctrl+输入文字换行符J

所以,你可以这样做:

IFS= read -e -rd $'\r' -p 'text: ' text
printf 'Got: <%s>\n' "$text"

请注意,它不允许您^M在文本中嵌入字符。尽管您可以使用-d ''而不是读取直到 NUL 并使用+-d $'\r'提交文本,而不是因为 bash 变量不能包含 NUL 字符。CtrlSpaceEnter

readline现在还支持括号粘贴,较新的版本也默认启用它。对于旧版本,您可以添加:

set enable-bracketed-paste`

~/.inputrc或添加:

bind 'set enable-bracketed-paste' 2> /dev/null

到调用之前的脚本read


或者您可以使用 moreutils'vipe运行用户首选的编辑器来输入文本:

text=$(vipe</dev/null)

如果你没有vipe, in zsh,你可以这样做:

(){
  ${VISUAL:-${EDITOR:-vi}} $1
  text=$(<$1)
} =()

当心那些删除尾随换行符的操作。


可以使用以下所有方法完成预播种:

text=seed; vared -p 'text: ' text
IFS= read -e -rd $'\r' -i seed -p 'text: ' text
text=$(echo seed | vipe)
(){
  ${VISUAL:-${EDITOR:-vi}} $1
  text=$(<$1)
} =(echo seed)

另请注意,除了第read -e一个之外,所有这些解决方案都只能交互工作。echo some text | those-scripts例如,你将无法做到。但是,您可以添加一个检查来查看 stdin 是否来自终端,并text=$(cat)在不是来自终端时使用:

if [ -t 0 ]; then
  # stdin is a terminal, use any of the solutions above
else
  text=$(cat)
fi

相关内容