Trim AWK 中的额外空格
Trim extra spaces in AWK
我有这个 AWK 脚本。
awk -v line=" foo bar " 'END
{
gsub(/^ +| +$/,"", line);
gsub(/ {2,}/, " ", line);
print line
}' \
somefile.txt
输入文件(somefile.txt)与我的问题无关。 END
模式之后的部分是在 line
变量中 trim 额外的空格 并将其打印出来。像这样:
foo bar
我想看看在 AWK 中是否有更好、更紧凑的方法来做到这一点。使用 gsub
删除几个额外的空格非常麻烦。它很难阅读,维护者也很难理解它的作用(特别是如果以前从未使用过 AWK)。关于如何使其更短或更明确的任何想法?
谢谢!
** 编辑 **
AWK 变量 line
在输入文件的 awk 处理过程中被过滤,我想 trim 在那之后留下额外的空间。
我在 路径上:
$ awk -v line=" foo bar " '
BEGIN {
[=10=]=line
for(i=1;i<=NF;i++)
printf "%s%s",$i,(i==NF?ORS:OFS)
}'
输出:
foo bar
您开始时使用 gsub()
的另一个选项可以完成为:
awk '{gsub(/ +/," "); sub(/^ /,""); sub(/ $/,"")}1' <<< " foo bar "
第一次调用 gsub()
将所有多个 space 合并为一个 space before/between 字段。第二个 sub(/^ /,"")
只是修剪保留在字符串前面的单个 space,最后一个 sub(/ $/,"")
修剪尾随的 space.
这两种方法都适用。根据您的实际数据和您的 FS
值,可能会偏爱其中一个,但在不知道更多的情况下,它们几乎是一种洗礼。
例子Use/Output
$ awk '{gsub(/ +/," "); sub(/^ /,""); sub(/ $/,"")}1' <<< " foo bar "
foo bar
使用您显示的示例,请尝试执行以下 awk
程序。因为你有一个 awk
变量并且你没有读取任何 Input_file 那么我们不需要使用 END
块我们实际上可以在 [=12= 中使用 BEGIN
块本身] 读取变量的程序。
在这个 awk
程序中,我创建了名为 line
的 awk
变量,并且在这个程序的 BEGIN
部分,我全局替换了开始和结束 spaces 与 NULL THEN 行全局替换所有出现的 spaces(1 或更多)与变量 line
中的 OFS(它本身是一个 space),然后打印它的值。
awk -v line=" foo bar " '
BEGIN{
gsub(/^[[:space:]]+|[[:space:]]+$/,"",line)
gsub(/[[:space:]]+/,OFS,line)
print line
}
'
或 考虑到您的 awk
程序中还有其他 functions/tasks/work 发生并且您想进行修剪END
部分中的变量然后尝试以下
awk -v line=" foo bar " '
END{
gsub(/^[[:space:]]+|[[:space:]]+$/,"",line)
gsub(/[[:space:]]+/,OFS,line)
print line
}
' Input_file
使用split
函数收集数组中的所有字段并substr
删除最后一个前导space:
$ awk -vline=" foo bar " 'END {s = ""; l = split(line, a)
for(i = 1; i <= l; i++) s = s " " a[i]; print substr(s, 2) "X"}' /dev/null
foo barX
结尾的 X
在这里表示结尾的 space 也被删除了。如果您最终决定使用它,请抑制它。 patsplit
而不是 split
的其他解决方案:
$ awk -vline=" foo bar " 'END {s = ""; l = patsplit(line, a, /[^ ]+/)
for(i = 1; i <= l; i++) s = s " " a[i]; print substr(s, 2) "X"}' /dev/null
foo barX
对于当前示例,另一个选项可能是 recalculate the text 输入记录,方法是首先将行的值设置为输入记录,然后使用 =
awk -v line=" foo bar " 'END {[=10=]=line; =; print}' somefile.txt
输出(引号只是为了清楚,没有前导或尾随 spaces)
"foo bar"
Ed Morton 的评论中描述了如何删除 space 的内部工作原理:
设置 [=13=]=line
或对 [=14=]
的任何其他更改将触发重新计算 字段 。
使用 =
会触发 记录 重新计算,因为它将从现有字段中重建,从而剥离 leading/trailing 白色 space 并用单个空白字符替换所有其他相邻的白色链 space(假设使用默认的 FS 和 OFS)。
如果你的 space 都是空白字符,那么使用 FS
的任何值和 OFS
的任何值的任何 awk 都是由你的问题中的代码处理的,这里是如何按照您的问题中的要求简要而明确地进行:
gsub(/ +/, " ", line)
gsub(/^ | $/, "", line)
例如,假设您有一个 CSV 文件,并希望打印每行中的字段数,然后是用 |
分隔的字段。示例输入文件为:
$ cat file
stuff,nonsense
要处理的 awk 脚本是:
$ awk -v FS=',' -v OFS='|' '
{ print NF, , }
' file
2|stuff|nonsense
现在让我们介绍您的 line
变量及其相关处理(我在输出中添加了 <
和 >
以表明 leading/trailing space s 被剥离):
$ awk -v line=' foo bar ' -v FS=',' -v OFS='|' '
{ print NF, , }
END {
gsub(/ +/, " ", line)
gsub(/^ | $/, "", line)
print "<" line ">"
}
' file
2|stuff|nonsense
<foo bar>
如您所见,一切都完全按预期工作,而到目前为止发布的所有其他解决方案都会以各种方式失败。
如果 line
中的 space 不全是空白,则对 line
中任何类型的白色 space 字符使用 POSIX awk (使用 non-POSIX awk 将 [[:space:]]
替换为 [ \t]
以捕获最常见的空白字符和制表符,根据需要添加其他字符):
gsub(/[[:space:]]+/, " ", line)
gsub(/^ | $/, "", line)
您的脚本:
gsub(/^ +| +$/,"", line);
gsub(/ {2,}/, " ", line);
比它必须的要长,因为你以错误的顺序执行 gsub()s,这需要第一个中的 +
s 并且不必要地检查 2 个或更多空白({2,}
) 在第二个。如果某些 space 是制表符或其他一些白色 space 字符,它也不会工作。
我有这个 AWK 脚本。
awk -v line=" foo bar " 'END
{
gsub(/^ +| +$/,"", line);
gsub(/ {2,}/, " ", line);
print line
}' \
somefile.txt
输入文件(somefile.txt)与我的问题无关。 END
模式之后的部分是在 line
变量中 trim 额外的空格 并将其打印出来。像这样:
foo bar
我想看看在 AWK 中是否有更好、更紧凑的方法来做到这一点。使用 gsub
删除几个额外的空格非常麻烦。它很难阅读,维护者也很难理解它的作用(特别是如果以前从未使用过 AWK)。关于如何使其更短或更明确的任何想法?
谢谢!
** 编辑 **
AWK 变量 line
在输入文件的 awk 处理过程中被过滤,我想 trim 在那之后留下额外的空间。
我在
$ awk -v line=" foo bar " '
BEGIN {
[=10=]=line
for(i=1;i<=NF;i++)
printf "%s%s",$i,(i==NF?ORS:OFS)
}'
输出:
foo bar
您开始时使用 gsub()
的另一个选项可以完成为:
awk '{gsub(/ +/," "); sub(/^ /,""); sub(/ $/,"")}1' <<< " foo bar "
第一次调用 gsub()
将所有多个 space 合并为一个 space before/between 字段。第二个 sub(/^ /,"")
只是修剪保留在字符串前面的单个 space,最后一个 sub(/ $/,"")
修剪尾随的 space.
这两种方法都适用。根据您的实际数据和您的 FS
值,可能会偏爱其中一个,但在不知道更多的情况下,它们几乎是一种洗礼。
例子Use/Output
$ awk '{gsub(/ +/," "); sub(/^ /,""); sub(/ $/,"")}1' <<< " foo bar "
foo bar
使用您显示的示例,请尝试执行以下 awk
程序。因为你有一个 awk
变量并且你没有读取任何 Input_file 那么我们不需要使用 END
块我们实际上可以在 [=12= 中使用 BEGIN
块本身] 读取变量的程序。
在这个 awk
程序中,我创建了名为 line
的 awk
变量,并且在这个程序的 BEGIN
部分,我全局替换了开始和结束 spaces 与 NULL THEN 行全局替换所有出现的 spaces(1 或更多)与变量 line
中的 OFS(它本身是一个 space),然后打印它的值。
awk -v line=" foo bar " '
BEGIN{
gsub(/^[[:space:]]+|[[:space:]]+$/,"",line)
gsub(/[[:space:]]+/,OFS,line)
print line
}
'
或 考虑到您的 awk
程序中还有其他 functions/tasks/work 发生并且您想进行修剪END
部分中的变量然后尝试以下
awk -v line=" foo bar " '
END{
gsub(/^[[:space:]]+|[[:space:]]+$/,"",line)
gsub(/[[:space:]]+/,OFS,line)
print line
}
' Input_file
使用split
函数收集数组中的所有字段并substr
删除最后一个前导space:
$ awk -vline=" foo bar " 'END {s = ""; l = split(line, a)
for(i = 1; i <= l; i++) s = s " " a[i]; print substr(s, 2) "X"}' /dev/null
foo barX
结尾的 X
在这里表示结尾的 space 也被删除了。如果您最终决定使用它,请抑制它。 patsplit
而不是 split
的其他解决方案:
$ awk -vline=" foo bar " 'END {s = ""; l = patsplit(line, a, /[^ ]+/)
for(i = 1; i <= l; i++) s = s " " a[i]; print substr(s, 2) "X"}' /dev/null
foo barX
对于当前示例,另一个选项可能是 recalculate the text 输入记录,方法是首先将行的值设置为输入记录,然后使用 =
awk -v line=" foo bar " 'END {[=10=]=line; =; print}' somefile.txt
输出(引号只是为了清楚,没有前导或尾随 spaces)
"foo bar"
Ed Morton 的评论中描述了如何删除 space 的内部工作原理:
设置 [=13=]=line
或对 [=14=]
的任何其他更改将触发重新计算 字段 。
使用 =
会触发 记录 重新计算,因为它将从现有字段中重建,从而剥离 leading/trailing 白色 space 并用单个空白字符替换所有其他相邻的白色链 space(假设使用默认的 FS 和 OFS)。
如果你的 space 都是空白字符,那么使用 FS
的任何值和 OFS
的任何值的任何 awk 都是由你的问题中的代码处理的,这里是如何按照您的问题中的要求简要而明确地进行:
gsub(/ +/, " ", line)
gsub(/^ | $/, "", line)
例如,假设您有一个 CSV 文件,并希望打印每行中的字段数,然后是用 |
分隔的字段。示例输入文件为:
$ cat file
stuff,nonsense
要处理的 awk 脚本是:
$ awk -v FS=',' -v OFS='|' '
{ print NF, , }
' file
2|stuff|nonsense
现在让我们介绍您的 line
变量及其相关处理(我在输出中添加了 <
和 >
以表明 leading/trailing space s 被剥离):
$ awk -v line=' foo bar ' -v FS=',' -v OFS='|' '
{ print NF, , }
END {
gsub(/ +/, " ", line)
gsub(/^ | $/, "", line)
print "<" line ">"
}
' file
2|stuff|nonsense
<foo bar>
如您所见,一切都完全按预期工作,而到目前为止发布的所有其他解决方案都会以各种方式失败。
如果 line
中的 space 不全是空白,则对 line
中任何类型的白色 space 字符使用 POSIX awk (使用 non-POSIX awk 将 [[:space:]]
替换为 [ \t]
以捕获最常见的空白字符和制表符,根据需要添加其他字符):
gsub(/[[:space:]]+/, " ", line)
gsub(/^ | $/, "", line)
您的脚本:
gsub(/^ +| +$/,"", line);
gsub(/ {2,}/, " ", line);
比它必须的要长,因为你以错误的顺序执行 gsub()s,这需要第一个中的 +
s 并且不必要地检查 2 个或更多空白({2,}
) 在第二个。如果某些 space 是制表符或其他一些白色 space 字符,它也不会工作。