【问题标题】:removing last character of every word in files删除文件中每个单词的最后一个字符
【发布时间】:2017-05-01 00:42:39
【问题描述】:

我有多个文件,只有一行简单的文本。我想删除每个文件中每个单词的最后一个字符。每个文件都有不同的文本长度。

我得到的最接近的是编辑一个文件:

awk '{ print substr($1, 1, length($1)-1); print substr($2, 1, length($2)-1); }' file.txt

但我不知道如何使这个通用,对于不同单词的文件计数。

【问题讨论】:

  • 可以肯定的是,1 line of simple textevery word表示每个文件有1行,里面有0到几个单词,每个单词必须修改(看到很多回复只删除了该行的最后一个字符)
  • 是的,里面其实有1到几个字

标签: regex bash text awk replace


【解决方案1】:
awk '{for(x=1;x<=NF;x++)sub(/.$/,"",$x)}7' file

这应该可以删除。

如果测试没问题,并且你想覆盖你的文件,你可以这样做:

awk '{for(x=1;x<=NF;x++)sub(/.$/,"",$x)}7' file > tmp && mv tmp file

例子:

kent$  awk '{for(x=1;x<=NF;x++)sub(/.$/,"",$x)}7' <<<"foo bar foobar"   
fo ba fooba

【讨论】:

  • 7 打印一行很有趣,7 的特殊含义而不是频繁的 1 用于此目的?
  • 是的,特殊含义是幸运数字! :-D 开个玩笑.. 7 对我来说更容易达到。我觉得右手食指比左手小指方便。你知道,一个重度 vim 用户关心击键
【解决方案2】:

使用awk 循环直到每行中的最大字段达到NF,并应用substr 函数。

awk '{for (i=1; i<=NF; i++) {printf "%s ", substr($i, 1, length($i)-1)}}END{printf "\n"}' file

对于样本输入file

ABCD ABC BC

awk 逻辑产生一个输出

ABC AB B

另一种方法是将记录分隔符更改为 NULL 并仅使用 print:-

awk 'BEGIN{ORS="";}{for (i=1; i<=NF; i++) {print substr($i, 1, length($i)-1); print " "}}END{print "\n"}' file

【讨论】:

    【解决方案3】:

    我会选择 Bash 方法:

    ${var%?} removes the last character of a variable:

    $ var="hello"
    $ echo "${var%?}"
    hell
    

    还有you can use the same approach on arrays:

    $ arr=("hello" "how" "are" "you")
    $ printf "%s\n" "${arr[@]%?}"
    hell
    ho
    ar
    yo
    

    如何浏览文件,将它们唯一的一行(你说文件只包含一行)读入一个数组并使用上述工具删除每个单词的最后一个字符:

    for file in dir/*; do
       read -r -a myline < "$file"
       printf "%s " "${myline[@]%?}"
    done
    

    【讨论】:

    • 我唯一关心的是使用像这样的纯bash 逻辑时文件的大小限制。与awk相比,处理大文件真的很慢吗?
    • @Inian 我们应该对其进行测试。但是,解析多个单行文件似乎并不是一项非常耗费 CPU 的任务,因此关心性能更多的是学术争论。
    • 话虽如此,也建议记住这个答案:Why is using a shell loop to process text considered bad practice?
    • 谢谢!由于考虑到了这个特定的主题,所以首先提出了这个问题:)
    【解决方案4】:

    Sed 版本,假设单词仅由字母组成(如果不是,只需调整类 [[:alpha:]] 以反映您的需要)并用空格和标点分隔

    sed 's/$/ /;s/[[:alpha:]]\([[:blank:][:punct:]]\)/\1/g;s/ $//' YourFile
    

    awk(实际上是正则表达式边界)

     gawk '{gsub(/.\>/, "");print}' YourFile
    
     #or optimized by @kent ;-) thks for the tips
     gawk '4+gsub(/.\>/, "")' YourFile
    

    【讨论】:

    • 如果高尔夫有点迷糊,你可以做gawk '7+gsub(...)' file
    • 不知道7+gsub 是“模式匹配器”,很好的提示
    【解决方案5】:
    $ cat foo
    word1
    word2 word3
    $ sed 's/\([^ ]*\)[^ ]\( \|$\)/\1\2/g' foo
    word
    word word
    

    单词是任何字符串,不包括空格 (=[^ ])。

    编辑:如果你想强制执行 POSIX (--posix),你可以使用:

    $ sed --posix 's/\([^ ]*\)[^ ]\([ ]\{,1\}\)/\1\2/g' foo
    word
    word word
    

    这个\( \|$\)改成\([ ]\{,1\}\),即末尾有一个可选的空格。

    【讨论】:

    • 使用 GNU sed,posix 因\| 失败(在我的 sed 中添加/删除空间的原因)
    • 没有注意到需要posix。
    • 不是批评者,只是告诉一个限制,即使它越来越多地用于不存在这种限制的 linux 上。在这里,我的一半系统仍然是没有 gawk ou gnu sed 的 aix(或 sun),我必须适应。
    • @NeronLeVelu 已修复(希望 :)。
    猜你喜欢
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    • 1970-01-01
    • 2018-03-27
    • 2013-09-22
    • 2016-01-21
    相关资源
    最近更新 更多