ChatGPT解决这个技术问题 Extra ChatGPT

如何使用 sed 删除尾随空格?

我有一个简单的 shell 脚本,可以从文件中删除尾随空格。有什么方法可以使这个脚本更紧凑(不创建临时文件)?

sed 's/[ \t]*$//' $1 > $1__.tmp
cat $1__.tmp > $1
rm $1__.tmp
您可以使用 mv 代替 catrm。你为什么要这样使用cat?为什么不使用 cp
我使用从这个问题中学到的知识来创建 a shell script for recursively removing trailing whitespace
由于 Windows 上 sed 中的错误,您的解决方案在使用 MinGW 时实际上更好:stackoverflow.com/questions/14313318/…
请注意,使用 cat 而不是 mv 覆盖原始文件实际上会替换原始文件中的数据(即,它不会破坏硬链接)。使用许多解决方案中建议的 sed -i 不会做到这一点。 IOW,继续做你正在做的事情。

T
Tom McClure

对于 Linux 和 Unix,您可以使用 sed 的就地选项 -i

sed -i 's/[ \t]*$//' "$1"

请注意,该表达式将删除 OSX 上的尾随 t(您可以使用 gsed 来避免此问题)。它也可能在 BSD 上删除它们。

如果您没有 gsed,以下是 OSX 上正确(但难以阅读)的 sed 语法:

sed -i '' -E 's/[ '$'\t'']+$//' "$1"

三个单引号字符串最终连接成一个参数/表达式。 bash 中没有连接运算符,您只需将字符串一个接一个地放置,中间没有空格。

$'\t' 解析为 bash 中的文字制表符(使用 ANSI-C quoting),因此制表符正确连接到表达式中。


我的机器上出现以下无法更新的信息:sed: Not a recognized flag: i
嗯。从某种意义上说,它也有问题,它会删除所有尾随的“t”:)
“sed: Not a known flag: i –” 这发生在 OSX 上。您需要在 Mac 上的 -i 之后添加备份文件的扩展名。例如: sed -i .bak 's/[ \t]*$//' $1
@GoodPerson 如果您不是在开玩笑,您可能会忘记转义 t :) \t 是一个标签,供那些可能还不知道的人使用。
@SeanAllred 不是在开玩笑:除非您碰巧使用 GNU sed,否则它完全坏掉了(它在很多其他方面都坏掉了)
A
Asclepius

至少在 Mountain Lion 上,Viktor 的回答也会在字符 't' 位于行尾时删除它。以下修复了该问题:

sed -i '' -e's/[[:space:]]*$//' "$1"

我的 sed 还想要一个表示“扩展(现代)正则表达式”的 -E
codaddict 的答案在 OS X(现在的 macOS)上有同样的问题。这是该平台上唯一的解决方案。
El Capitan 上的 @JaredBeck Mine sed 没有。
谢谢!所以修剪:|sed -r -e 's"^[[:space:]]*""' -e 's"[[:space:]]*$""'“`
A
Asclepius

感谢 codaddict 建议使用 -i 选项。

下面的命令解决了雪豹上的问题

sed -i '' -e's/[ \t]*$//' "$1"

就像@acrollet 所说,除了 GNU sed 之外,您不能将 \t 与 sed 一起使用,它会被解释为文字字母 t。该命令似乎只起作用,可能是因为文件中结尾的空格中没有制表符,也没有 t。不建议使用 '' 而不指定备份后缀。
如果仅针对 Snow Leopard 指示该分辨率,那么问题可能应该是“如何删除 Macos 上的尾随空格????”
S
Scrutinizer

最好也报价 1 美元:

sed -i.bak 's/[[:blank:]]*$//' "$1"

S
Sandip Patel - SM
var1="\t\t Test String trimming   "
echo $var1
Var2=$(echo "${var1}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
echo $Var2

嘿,这正是我需要的!发布的其他 sed 解决方案在我的 bash 脚本中与管道(以及管道和管道......)变量分配集成时存在问题,但您的解决方案是开箱即用的。
P
Pascal T.

我的 .bashrc 中有一个在 OSX 和 Linux 下工作的脚本(仅限 bash!)

function trim_trailing_space() {
  if [[ $# -eq 0 ]]; then
    echo "$FUNCNAME will trim (in place) trailing spaces in the given file (remove unwanted spaces at end of lines)"
    echo "Usage :"
    echo "$FUNCNAME file"
    return
  fi
  local file=$1
  unamestr=$(uname)
  if [[ $unamestr == 'Darwin' ]]; then
    #specific case for Mac OSX
    sed -E -i ''  's/[[:space:]]*$//' $file
  else
    sed -i  's/[[:space:]]*$//' $file
  fi
}

我补充说:

SRC_FILES_EXTENSIONS="js|ts|cpp|c|h|hpp|php|py|sh|cs|sql|json|ini|xml|conf"

function find_source_files() {
  if [[ $# -eq 0 ]]; then
    echo "$FUNCNAME will list sources files (having extensions $SRC_FILES_EXTENSIONS)"
    echo "Usage :"
    echo "$FUNCNAME folder"
    return
  fi
  local folder=$1

  unamestr=$(uname)
  if [[ $unamestr == 'Darwin' ]]; then
    #specific case for Mac OSX
    find -E $folder -iregex '.*\.('$SRC_FILES_EXTENSIONS')'
  else
    #Rhahhh, lovely
    local extensions_escaped=$(echo $SRC_FILES_EXTENSIONS | sed s/\|/\\\\\|/g)
    #echo "extensions_escaped:$extensions_escaped"
    find $folder -iregex '.*\.\('$extensions_escaped'\)$'
  fi
}

function trim_trailing_space_all_source_files() {
  for f in $(find_source_files .); do trim_trailing_space $f;done
}

y
yolenoyer

对于那些寻求效率的人(要处理的许多文件或大型文件),使用 + 重复运算符而不是 * 可使命令快两倍以上。

使用 GNU sed:

sed -Ei 's/[ \t]+$//' "$1"
sed -i 's/[ \t]\+$//' "$1"   # The same without extended regex

我还快速对其他东西进行了基准测试:使用 [ \t] 而不是 [[:space:]] 也显着加快了进程(GNU sed v4.4):

sed -Ei 's/[ \t]+$//' "$1"

real    0m0,335s
user    0m0,133s
sys 0m0,193s

sed -Ei 's/[[:space:]]+$//' "$1"

real    0m0,838s
user    0m0,630s
sys 0m0,207s

sed -Ei 's/[ \t]*$//' "$1"

real    0m0,882s
user    0m0,657s
sys 0m0,227s

sed -Ei 's/[[:space:]]*$//' "$1"

real    0m1,711s
user    0m1,423s
sys 0m0,283s

D
David Tonhofer

纯娱乐:

#!/bin/bash

FILE=$1

if [[ -z $FILE ]]; then
   echo "You must pass a filename -- exiting" >&2
   exit 1
fi

if [[ ! -f $FILE ]]; then
   echo "There is not file '$FILE' here -- exiting" >&2
   exit 1
fi

BEFORE=`wc -c "$FILE" | cut --delimiter=' ' --fields=1`

# >>>>>>>>>>
sed -i.bak -e's/[ \t]*$//' "$FILE"
# <<<<<<<<<<

AFTER=`wc -c "$FILE" | cut --delimiter=' ' --fields=1`

if [[ $? != 0 ]]; then
   echo "Some error occurred" >&2
else
   echo "Filtered '$FILE' from $BEFORE characters to $AFTER characters"
fi

D
Dan Martinez

sed 的特定情况下,其他人已经提到的 -i 选项无疑是最简单和最明智的选项。

在更一般的情况下,来自 moreutils 集合的 sponge 完全符合您的要求:它允许您将文件替换为处理它的结果,以一种专门设计的方式来防止处理步骤自身发生故障通过覆盖它正在处理的文件。引用 sponge 手册页:

海绵读取标准输入并将其写入指定文件。与 shell 重定向不同,海绵在写入输出文件之前会吸收其所有输入。这允许构建读取和写入同一文件的管道。

https://joeyh.name/code/moreutils/


w
will

这些答案让我很困惑。这两个 sed 命令都适用于 Java 源文件:

sed 's/\s\+$/ 文件名

sed 's/[[:space:]]\+$// 文件名

出于测试目的,我使用了:

 $ echo "  abc       " | sed 's/\s\+$/-xx/'
abc-xx
 $ echo -e "  abc   \t\t    " | sed 's/\s\+$/-xx/'
abc-xx

用“-xx”替换所有尾随空格。

@Viktor 希望避免临时文件,我个人只会使用 -i =>就地带有备份后缀。至少在我知道该命令有效之前。

抱歉,我只是发现现有的回复有点倾斜sed 是简单的工具。在 90% 的情况下,以直接的方式更容易接近它。或者也许我错过了一些东西,很高兴在那里纠正。


T
Thorkil Værge

要删除当前目录中所有文件的尾随空格,我使用

ls | xargs sed -i 's/[ \t]*$//'

p
phk

仅从具有至少一个非空格字符的行中去除空格(在我的情况下为空格和制表符)(这样就不会触及空的缩进行):

sed -i -r 's/([^ \t]+)[ \t]+$/\1/' "$file"