#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