Как мне уменьшить все индексы массива в текстовом файле?

#awk #sed #substitution #cat #xargs

#awk #sed #замена #cat #xargs

Вопрос:

Предыстория

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

 $SomeText.element_[1]="MoreText[3]";r"
$SomeText.element_[2]="MoreText[6]";r"
$SomeText.element_[3]="MoreText[2]";r"
$SomeText.element_[4]="MoreText[1]";r"
$SomeText.element_[5]="MoreText[5]";r"
  

Это продолжается более тысячи строк. Я хочу сделать следующее:

 $SomeText.element_[0]="MoreText[3]";r"
$SomeText.element_[1]="MoreText[6]";r"
$SomeText.element_[2]="MoreText[2]";r"
$SomeText.element_[3]="MoreText[1]";r"
$SomeText.element_[4]="MoreText[5]";r"
  

В каждой строке текста в файле самый левый индекс должен быть уменьшен на единицу, при этом остальной текст не должен изменяться.

Попытки решения

До сих пор я пробовал следующее…но проблема для меня в том, что я не знаю, как правильно передать его обратно в файл:

Попытка 1

Я попробовал метод двойного сокращения:

 cat file.txt | cut -d '[' -f2 | cut -d ']' -f1 | xargs -I {} expr {}   1
  

Это правильно выводит все индексы, уменьшенные на единицу, в командную строку.

Попытка 2

Я пытался использовать awk со смесью sed, но это привело к зависанию компьютера:

 awk -F'[' '{printf("%dn", $2-1)}' file.txt | xargs -I {} sed -i 's/[d ]/{}/g' file.txt
  

Вопрос

Как мне правильно уменьшить все индексы массива в файле на единицу и правильно записать уменьшенные индексы в нужное расположение текстового файла?

Комментарии:

1. обратите внимание, что d это не поддерживается sed , смотрите Также Почему мое регулярное выражение работает в X, но не в Y?

Ответ №1:

Однострочник Perl упрощает это, перезаписывая входной файл:

 perl -pi -e 's/(d )/$1-1/e' your-file-name-here
  

(предполагается, что первое число в каждой строке является индексом)

Комментарии:

1. вы также могли бы использовать s/d /$amp;-1/e и s/[Kd (?=])/$amp;-1/e для замены первых цифр внутри []

Ответ №2:

С помощью simple awk вы могли бы попробовать следующее, написанное и протестированное с показанными примерами.

 awk '
match($0,/[[^]]*/){
  print substr($0,1,RSTART) count   substr($0,RSTART RLENGTH)
}
' Input_file
  

Или, если количество ваших входных файлов между ними [..] находится в любом порядке, просто уменьшите 1 их следующим образом.

 awk '
match($0,/[[^]]*/){
  print substr($0,1,RSTART) substr($0,RSTART 1,RLENGTH)-1 substr($0,RSTART RLENGTH)
}
' Input_file
  

Ответ №3:

С помощью GNU sed и bash :

 sed -E "s/([^[]*[)([0-9] )(].*)/printf '%s%d%sn' '1' $((2 - 1)) '3'/e" file
  

Или, если возможно, что строки содержат ' символ:

 sed -E "
/[[0-9] ]/{
    s/'/'\''/g
    s/([^[]*[)([0-9] )(].*)/printf '%s%d%sn' '1' $((2 - 1)) '3'/e
}" file