我有以下变量。
echo "|$COMMAND|"
返回
|
REBOOT|
如何删除第一个换行符?
tr
命令可以被${parameter/pattern/string}
替换,这是一种bashism。COMMAND=$'\nREBOOT\r \n'
echo "|${COMMAND}|"
|
OOT
|
echo "|${COMMAND//[$'\t\r\n']}|"
|REBOOT |
echo "|${COMMAND//[$'\t\r\n ']}|"
|REBOOT|
man -Pless\ +/parameter/pattern/string bash
man -Pless\ +/\/pattern bash
man -Pless\ +/\\\'string\\\' bash
man -Pless\ +/^\\\ *Parameter\\\ Exp bash
man -Pless\ +/^\\\ *QUOTING bash
${parameter//pattern/string}
If there are two slashes separating parameter and pattern,
all matches of pattern are replaced with string.
进一步...COMMAND=$' \n RE BOOT \r \n'
echo "|$COMMAND|"
|
BOOT
|
read -r COMMAND <<<"${COMMAND//[$'\t\r\n']}"
echo "|$COMMAND|"
|RE BOOT|
回答Vulwsztyn的问题:
为什么当模式为空时,这个方法能够工作?
在 ${COMMAND//[$'\t\r\n ']}
中:
/
的意思是:模式替换(遵循 ${parameter/pattern/string}
的语法)/[$'\r\n ']
,以 /
开头,然后将所有匹配的模式替换为 string
string
是空的(因为没有第二个斜杠跟随任何 string
...)。nothing
,例如两个连续的空格(然后你可以在替换的字符串后面再添加两个空格以平衡输出):echo "|${COMMAND//*()/ } |"
| R E B O O T |
COMMAND=$'\nREBOOT\r \n'
echo ${COMMAND@Q}
$'\nREBOOT\r \n'
COMMAND=$(echo $COMMAND|tr -d '\n\t\r ')
echo ${COMMAND@Q}
'REBOOT'
那么
time for i in {1..1000};do
COMMAND=$'\nREBOOT\r \n'
COMMAND=$(echo $COMMAND|tr -d '\n\t\r ')
done;echo ${COMMAND@Q}
real 0m2.785s
user 0m2.296s
sys 0m0.774s
'REBOOT'
用
COMMAND=$'\nREBOOT\r \n'
COMMAND="${COMMAND//[$'\t\r\n ']}"
echo ${COMMAND@Q}
time for i in {1..1000};do
COMMAND=$'\nREBOOT\r \n'
COMMAND="${COMMAND//[$'\t\r\n ']}"
done;echo ${COMMAND@Q}
real 0m0.006s
user 0m0.001s
sys 0m0.004s
'REBOOT'
在我的主机上,使用1,000个fork来执行tr
需要超过2700毫秒的时间,而使用内置的bash参数扩展相同的任务只需要6毫秒(快了464.2倍!)。
注意:实际上:var=$(echo | tr x y)
会导致两个fork,而不仅仅是一个!通过使用以下语法,您可以避免1个(x1000)fork,从而使速度稍微更快:
time for i in {1..1000};do
COMMAND=$'\nREBOOT\r \n'
COMMAND=$( tr -d '\n\t\r ' <<<"$COMMAND" )
done;echo ${COMMAND@Q}
real 0m2.181s
user 0m1.590s
sys 0m0.566s
'REBOOT'
通过删除所有换行符来清理您的变量:
COMMAND=$(echo $COMMAND|tr -d '\n')
tr -d '\r'
才对吧? - Izzytr
命令。只需执行 COMMAND=$(echo $COMMAND)
即可获得类似的效果。这可能会产生新的进程,看起来有些麻烦,但对于人眼来说很简短清晰,如果你能抽出一两秒的时间,也许愿意尝试一下 :-)。 - Mike S${COMMAND//[$'\t\r\n']}
。 - Summer-Skyecho $COMMAND
(缺少引号) 的问题,点赞+1。但是_这是一个反模式,不应该使用_,因为如果存在任何全局通配符(例如 *
、[...]
或 ?
),它们也会被扩展。所以除非你的变量实际上是一个你想要扩展的通配符,否则永远不要使用未引用的扩展。 - gniourf_gniourfecho "|$COMMAND|"|tr '\n' ' '
将换行符(在POSIX / Unix中不是回车符)替换为空格。
说实话,我会考虑从bash切换到更稳健的东西。或者在第一次生成这种畸形数据时避免它。
嗯,这似乎也可能是一个可怕的安全漏洞,具体取决于数据来自何处。
tr -d '\n'
来代替用空格替换以删除换行符? - F. Hauri - Give Up GitHubtr '\n' ' ' <<< "|$COMMAND|"
替代 echo ... | ...
。 - F. Hauri - Give Up GitHub"|${COMMAND//$'\n'}|"
。意思是将变量 $COMMAND
中的所有换行符替换为空格,并用竖线 |
包围整个字符串。 - rici使用 bash
:
echo "|${COMMAND/$'\n'}|"
(请注意,此问题中的控制字符是“换行符”(\n
),而不是回车符(\r
)。后者会在一行上输出REBOOT|
。)
使用 Bash 的Shell参数扩展 ${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|
添加答案以展示使用tr剥离多个字符(包括\r)和使用sed,并且使用hexdump进行说明。
在我的情况下,我发现以awk打印行中最后一项|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 |
这与之相关: 什么是回车、换行和换页?
对我有用的是 echo $testVar | tr "\n" " "
这里的 testVar 包含了我的变量/脚本输出
如果你不想为像(tr, sed 或 awk)这样简单的任务产生进程,那么可以使用这个Bashism。Bash可以独自完成:
COMMAND=${COMMAND//$'\n'/}
来自文档:
${FOO//from/to} Replace all
${FOO/from/to} Replace first match
CLEANED=${COMMAND//[$'\t\r\n']}
。我不是因为它在编写bash脚本时有效而投反对票,而是因为它出现在F. Hauri的回答之前,后者更完整,包括指向man页面等内容。它没有添加任何新内容。 - Mike Sshopt -s extglob
COMMAND=$'\nRE BOOT\r \n'
echo "|${COMMAND%%*([$'\t\r\n '])}|"
|
RE BOOT|
或者将%%替换为##以仅替换前导空格。
echo -n "|$COMMAND|"
。
$ man echo
-n
不输出尾随换行符。
为了解决实际问题的一个可能根源,有可能你正在使用一个crlf文件。
crlf示例:
.env (crlf)
VARIABLE_A="abc"
VARIABLE_B="def"
run.sh
#!/bin/bash
source .env
echo "$VARIABLE_A"
echo "$VARIABLE_B"
echo "$VARIABLE_A $VARIABLE_B"
返回:
abc
def
def
.env(lf)
VARIABLE_A="abc"
VARIABLE_B="def"
run.sh
#!/bin/bash
source .env
echo "$VARIABLE_A"
echo "$VARIABLE_B"
echo "$VARIABLE_A $VARIABLE_B"
返回:
abc
def
abc def
COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n ']}|"
返回|REBOOT|
。 - Alex Jordan\n
后面的空格以防止出现此问题:COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n']}|"
将返回|RE BOOT|
。 - F. Hauri - Give Up GitHub${COMMAND//[$'\t\r\n']}
中的模式是如何起作用的?我原以为${COMMAND//[\t\r\n]}
就可以了,但实际上并没有。$
符号和单引号又有什么作用呢? - haridsv