【问题标题】:Bash remove substring in file from stringBash从字符串中删除文件中的子字符串
【发布时间】:2018-11-20 14:22:48
【问题描述】:

我有一个这样的字符串:

myString='value1|value57|value31|value21'

我有一个名为 values_to_remove.txt 的文件,其中包含一个值列表,每行一个,以这种方式

values_to_remove.txt

value1
value31

在 bash 中,如何从字符串中删除“values_to_remove.txt”中包含的值,考虑到这些值是用管道分隔的,当然如果我删除一个值,我还必须删除前面的和跟随管道(如果有)。

我已经在 python 中实现了这一点,并从 bash 中调用了 python 脚本,但是我需要直接在 bash 中使用一行命令而不是小脚本来执行此操作,否则我已经可以使用我的小 python 脚本了。

这是python代码

myString = 'value1|value2|value3|value4'
arrString = myString.split("|")

with open("myfile.txt", encoding="utf-8") as file:
   for l in file:
       if  l in arrString:
           arrString.remove(l)

myNewString = "|".join(arrString)

注意:用管道分隔的值可以是任何字符串。

谢谢

【问题讨论】:

  • 我已经在 python 中完成了这项工作,并从 bash 中调用了 python 脚本,但我需要直接在 bash 中执行此操作
  • 我已经更新了问题并编辑了错误的部分
  • @Inian 的意思是用你编写的 python 代码更新帖子。
  • 添加了python代码,但我不明白你的要求。你以为我在撒谎吗?
  • @user2548436:没什么,只是这样,人们会更容易接受你的问题,如果他们看到为解决问题所做的一些努力/代码,而不是公然要求代码请求

标签: string bash replace


【解决方案1】:

你可以使用这个awk:

awk -v str="$myString" 'BEGIN {
   n = split(str, a, /\|/)
}
{
   val[$1]
}
END {
   for (i=1; i<=n; i++)
      if (!(a[i] in val))
         s = (s == "" ? "" : s "|") a[i]
   print s
}' values_to_remove.txt

value57|value21
  • 这个awk首先使用split函数来split|上的输入字符串
  • 它将所有要删除的值存储在另一个数组中val
  • 在结束块中,它循环遍历拆分数组,如果在要删除的数组中找不到值,则构建一个字符串。

【讨论】:

  • 感谢@anubhava 抽出宝贵时间。不幸的是,我已经在您回复后更新了问题,因为我需要一行命令。你知道怎么做吗?
  • 这只是一行,但我将其格式化为 si 以使其可读。您可以将其保留在一行中
【解决方案2】:

这是一个bash 解决方案(if 语句是运行时优化,以在不匹配的情况下跳过替换,感谢@Inian):

for val in value1 value31; do
    if [[ "$mystring" =~ \|$val|$val\| ]]; then
        mystring=${mystring/$BASH_REMATCH/}     
    fi
done

这会在纯 bash 中查找匹配 |valuevalue| 的第一个正则表达式并将其删除。请注意,您可以同时匹配两者,因为这样您将删除太多分隔符。如果有可能没有分隔符,您需要在每个管道之后使用?(也许第二个就足够了)。

您也可以避免使用正则表达式,只尝试删除前后管道:

for val in value1 value31; do 
    mystring=${mystring/|$val/};
    mystring=${mystring/$val|/}; 
done

如果你真的需要,所有这些都可以写在一行上:

 for val in value1 value31; do [[ "$mystring" =~ \|$val|$val\| ]]; mystring=${mystring/$BASH_REMATCH/}; done

【讨论】:

  • 正确。我会说这是一个运行时优化。
【解决方案3】:

纯 bash 解决方案:

#!/usr/bin/env bash

# Define the location of the values-to-be-removed file
: ${PATH_TO_FILE:=${1:-"./values_to_remove.txt"}}

# Define the string we will be working with
: ${MY_STRING:=${2:-"value1|value57|value31|value21"}}

# Process all entries in PATH_TO_FILE, one by one
while read -r substring || [[ -n "$line" ]]; do

  # Remove "substring|" from the beginning of MY_STRING
  MY_STRING=${MY_STRING#${substring}|}

  # Remove "|substring" from the rest of MY_STRING
  MY_STRING=${MY_STRING//|${substring}}

done < "${PATH_TO_FILE}"

# Return the results
echo ${MY_STRING}

我们为什么...

  • 使用${VAR_NAME:=${1:-"DEFAULT_VALUE"}} 表示法 - 允许用户通过环境变量或脚本参数自定义脚本的输入。基本上,这个符号表示:

    • 如果 VAR_NAME 环境变量存在,则使用它;
    • 如果 VAR_NAME 不存在,则将 VAR_NAME 设置为脚本第一个参数的值;
    • 如果第一个参数也不存在,则将 VAR_NAME 设置为 DEFAULT_VALUE。
  • 使用read -r substring || [[ -n "$line" ]] 读取文件? – read 允许我们逐行读取./values_to_remove.txt 文件的内容。 [[ -n "$line" ]] 位用于捕获文件中的最后一行,如果它不以换行符结尾。

参考文献

【讨论】:

    猜你喜欢
    • 2018-05-04
    • 2019-09-08
    • 1970-01-01
    • 2017-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多