我有一个简单的shell脚本,可以从文件中删除尾随空格。有没有办法让这个脚本更紧凑(没有创建临时文件)?
sed 's/[ \t]*$//' $1 > $1__.tmp
cat $1__.tmp > $1
rm $1__.tmp
答案 0 :(得分:135)
对于Linux和Unix,您可以使用-i
的就地选项sed
:
sed -i 's/[ \t]*$//' "$1"
请注意,该表达式将删除OSX上的尾随t
(您可以使用gsed
来避免此问题)。它也可以在BSD上删除它们。
如果你没有gsed,这是OSX上正确(但难以阅读)的sed语法:
sed -i '' -E 's/[ '$'\t'']+$//' "$1"
三个单引号字符串最终会连接成一个参数/表达式。在bash中没有连接运算符,你只需要一个接一个地放置字符串,中间没有空格。
$'\t'
解析为bash中的文字制表符(使用ANSI-C quoting),因此该制表符正确地连接到表达式中。
答案 1 :(得分:54)
至少在Mountain Lion上,Viktor的答案也会在一行结尾处删除字符't'。以下修复了该问题:
sed -i '' -e's/[[:space:]]*$//' "$1"
答案 2 :(得分:18)
感谢codaddict建议-i
选项。
以下命令解决了Snow Leopard上的问题
sed -i '' -e's/[ \t]*$//' "$1"
答案 3 :(得分:13)
最好还引用$ 1:
sed -i.bak 's/[[:blank:]]*$//' "$1"
答案 4 :(得分:4)
var1="\t\t Test String trimming "
echo $var1
Var2=$(echo "${var1}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
echo $Var2
答案 5 :(得分:3)
对于那些寻求效率(需要处理许多文件或大文件)的人来说,使用+
重复运算符而不是*
会使命令的速度提高两倍以上。
使用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
答案 6 :(得分:2)
我的.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
}
答案 7 :(得分:1)
只是为了好玩:
#!/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
答案 8 :(得分:0)
在sed
的特定情况下,其他人已经提到的-i
选项是最简单,最明智的选择。
在更一般的情况下,sponge
集合中的moreutils
可以完全满足您的要求:它允许您以处理文件的结果来替换文件,并采用专门设计的方式处理步骤是通过覆盖正在处理的文件跳闸自身。引用sponge
手册页:
sponge读取标准输入并将其写到指定文件中。与shell重定向不同,海绵在写入输出文件之前先吸收所有输入。这样就可以构造可读取和写入同一文件的管道。
答案 9 :(得分:-1)
仅从具有至少一个非空白字符的行中剥离空格(在我的情况下为空格和制表符)(这样就不会触及空的缩进行):
sed -i -r 's/([^ \t]+)[ \t]+$/\1/' "$file"