Bash удалить подстроку в файле из строки - PullRequest
0 голосов
/ 11 июня 2018

У меня есть одна строка, подобная этой:

myString='value1|value57|value31|value21'

, и у меня есть файл values_to_remove.txt, содержащий список значений, по одному на строку, таким образом

values_to_remove.txt

value1
value31

В bash, как я могу удалить значения, содержащиеся в "values_to_remove.txt", из строки, принимая во внимание, что значения разделены конвейером иКонечно, если я удаляю значение, я должен удалить также предыдущий и следующий канал, если таковые имеются.

Я достиг этого в python и вызвал скрипт python из bash, но мне нужно сделать это непосредственно в 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)

Обратите внимание: значения, разделенные конвейером, могут быть любыми строками.

Спасибо

Ответы [ 3 ]

0 голосов
/ 11 июня 2018

Вот решение bash (оператор if - это оптимизация во время выполнения, чтобы пропустить перестановку в случае несоответствия, спасибо @Inian):

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

Это выглядит чисто дляпервое регулярное выражение, которое соответствует либо |value или value| и удаляет его.Обратите внимание, что вы можете сопоставить оба параметра одновременно, потому что тогда вы удалите слишком много разделителей.Если есть вероятность, что нет разделителей, которые нужно использовать ? после каждого канала (может быть, достаточно только второго).

Вы также можете избежать регулярных выражений и просто попытаться удалить как предыдущий, так изадняя труба:

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
0 голосов
/ 11 июня 2018

Чистое решение для 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 в значение первого аргумента дляscript;
    • Если первый аргумент также не существует, установите для VAR_NAME значение DEFAULT_VALUE.
  • Используйте read -r substring || [[ -n "$line" ]] для чтения файла?- read позволяет нам читать содержимое файла ./values_to_remove.txt построчно.Бит [[ -n "$line" ]] предназначен для перехвата последней строки в файле, если он не заканчивается новой строкой.

Ссылки :

0 голосов
/ 11 июня 2018

Вы можете использовать это 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
  • В конечном блоке он циклически перебирает массив split и строит строку, если значение не найдено в том, чтобы бытьубранный массив.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...