如何在 Bash 中从字符串中删除换行符

我有以下变量。

echo "|$COMMAND|"

回来了

|
REBOOT|

如何删除第一个换行符?

307118 次浏览
echo "|$COMMAND|"|tr '\n' ' '

将用空格替换换行符(在 POSIX/Unix 中它不是回车符)。

老实说,我会考虑从 bash 切换到一些更理智的东西。或者一开始就避免生成这种畸形数据。

嗯,这似乎也是一个可怕的安全漏洞,这取决于数据来自哪里。

通过删除所有换行符来清理变量:

COMMAND=$(echo $COMMAND|tr -d '\n')

的领导下,存在一些抨击:

tr命令可以由 // 抨击代替:

COMMAND=$'\nREBOOT\r   \n'
echo "|${COMMAND}|"
|
OOT
|


echo "|${COMMAND//[$'\t\r\n']}|"
|REBOOT   |


echo "|${COMMAND//[$'\t\r\n ']}|"
|REBOOT|

请参阅 bash 手册页中的 参数展开引用:

man -Pless\ +/\/pattern bash
man -Pless\ +/\\\'string\\\' bash


man -Pless\ +/^\\\ *Parameter\\\ Exp bash
man -Pless\ +/^\\\ *QUOTING bash

再进一步。

正如@AlexJordan 所要求的,这将抑制 所有指定的字符。

COMMAND=$'         \n        RE BOOT      \r           \n'
echo "|$COMMAND|"
|
BOOT
|


CLEANED=${COMMAND//[$'\t\r\n']}
echo "|$CLEANED|"
|                 RE BOOT                 |


shopt -q extglob || { echo "Set shell option 'extglob' on.";shopt -s extglob;}


CLEANED=${CLEANED%%*( )}
echo "|$CLEANED|"
|                 RE BOOT|


CLEANED=${CLEANED##*( )}
echo "|$CLEANED|"
|RE BOOT|

简而言之:

COMMAND=$'         \n        RE BOOT      \r           \n'
CLEANED=${COMMAND//[$'\t\r\n']} && CLEANED=${CLEANED%%*( )}
echo "|${CLEANED##*( )}|"
|RE BOOT|

注意: 为了使用 *(...)语法,启用了 extglob选项(shopt -s extglob)。

如果您正在使用带有 extglobb 选项的 bash,您可以通过以下方式删除尾随的空格:

shopt -s extglob
COMMAND=$'\nRE BOOT\r   \n'
echo "|${COMMAND%%*([$'\t\r\n '])}|"

产出:

|
RE BOOT|

或者将%% 替换为 # # ,以仅替换前导空格。

使用 bash:

echo "|${COMMAND/$'\n'}|"

(注意,这个问题中的控制字符是一个‘ newline’(\n) ,而不是回车符(\r) ; 后者将在一行中输出 REBOOT|。)

解释

使用 Bash 壳参数展开 ${parameter/pattern/string}:

模式被扩展以生成一个模式,就像在文件名扩展中一样。展开 参数,将 模式与其值的最长匹配替换为 绳子。[ ... ]如果 绳子为空,则删除 模式的匹配项,并且可以省略 模式之后的 /

还使用 $'' ANSI-C 引用构造将换行指定为 $'\n'。直接使用换行符也可以,只是不那么漂亮:

echo "|${COMMAND/
}|"

完整的例子

#!/bin/bash
COMMAND="$'\n'REBOOT"
echo "|${COMMAND/$'\n'}|"
# Outputs |REBOOT|

或者,使用换行:

#!/bin/bash
COMMAND="
REBOOT"
echo "|${COMMAND/
}|"
# Outputs |REBOOT|

对我有效的是 echo $testVar | tr "\n" " "

TestVar 包含变量/script-output 的位置

您可以简单地使用 echo -n "|$COMMAND|"

$ man echo

-n不输出尾部换行符

添加答案以显示剥离多个字符(包括 r 使用 tr 和 sed)的示例。 并说明如何使用 hexdump。

在我的例子中,我发现以 awk print 结尾的命令行中最后一项 |awk '{print $2}'包含回车符 r 和引号。

我使用 sed 's/["\n\r]//g'去掉了回车和引号。

我也可以用 tr -d '"\r\n'

值得注意的是,如果想要删除 n 个换行字符,就需要 sed -z

$ COMMAND=$'\n"REBOOT"\r   \n'


$ echo "$COMMAND" |hexdump -C
00000000  0a 22 52 45 42 4f 4f 54  22 0d 20 20 20 0a 0a     |."REBOOT".   ..|


$ echo "$COMMAND" |tr -d '"\r\n' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |


$ echo "$COMMAND" |sed 's/["\n\r]//g' |hexdump -C
00000000  0a 52 45 42 4f 4f 54 20  20 20 0a 0a              |.REBOOT   ..|


$ echo "$COMMAND" |sed -z 's/["\n\r]//g' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |

这是相关的: 什么是回车、换行和换行?

  • CR = = r = = 0x0d
  • LF = = n = = 0x0a

为了解决实际问题的一个可能根源,您有可能正在寻找一个 crlf 文件。

CRLF 例子:

. env (crlf)

VARIABLE_A="abc"
VARIABLE_B="def"

跑,嘘

#!/bin/bash
source .env
echo "$VARIABLE_A"
echo "$VARIABLE_B"
echo "$VARIABLE_A $VARIABLE_B"

返回:

abc
def
def

不过,如果你转换成 LF:

VARIABLE_A="abc"
VARIABLE_B="def"

跑,嘘

#!/bin/bash
source .env
echo "$VARIABLE_A"
echo "$VARIABLE_B"
echo "$VARIABLE_A $VARIABLE_B"

返回:

abc
def
abc def

可以使用 Grep 过滤掉任何空行。如果您有几行数据并且希望删除任何空的数据,那么这非常有用。

echo "$COMMAND" | grep .

简短的回答 是最好的(请更改)使用这个 bashism 如果你不想为这样一个简单的任务产生(tr,sed 或 awk)进程,bash 可以单独完成:

COMMAND=${COMMAND//$'\n'/}

来自文件:

${FOO//from/to} Replace all
${FOO/from/to}  Replace first match

谢谢你的提醒,这是最好的答案。