Bash Scripting: заменить (или удалить) строку в файле, если строка начинается с (или совпадает) с другой строкой - PullRequest
2 голосов
/ 19 февраля 2011

Предполагая, что такой файл в стиле ini,

[Group]
Icon=xxx.ico
Title=An Image Editor
Description=Manipulates .ico, .png and .jpeg images

Я хочу заменить / удалить «.ico» ТОЛЬКО в строке, которая начинается с (или совпадает) «Icon =»

Я пытался это:

oldline="`cat "$file" | grep "Icon="`"
newline="`echo "$oldline" | tr ".ico" ".png"`"
cat "$oldfile" | tr "$oldline" "$newline" > $file

Тогда я понял, что tr работает совершенно иначе, чем я думал. Это НЕ традиционная функция «замени это». Поэтому я думаю, что правильный путь - это использование sed. Но:

  • Я никогда не использовал sed раньше. Понятия не имею, как это работает. Это излишне?
  • Если наиболее указанный способ действительно использует sed, учитывая, что он настолько мощный, есть ли какой-нибудь элегантный способ сделать это, кроме подхода «извлечь строку -> изменить строку -> заменить oldline для новой строки в файле»?

Примечания:

  • Я не могу заменить «.ico» глобально, я знаю, что это будет ОЧЕНЬ легче, я должен ограничить замену строкой Icon, в противном случае строка Описание также будет изменена.
  • Я новичок в написании сценариев оболочки в Linux, поэтому я ищу не только само решение, но и «правильный» способ сделать это. Элегантный, легко читаемый, обычный и т. Д.

Заранее спасибо!

Edit:

Спасибо, ребята! Вот окончательный сценарий, для справки:

#! /bin/bash
# Fix the following WARNING in ~/.xsession-errors
# gnome-session[2035]: EggSMClient-WARNING: Desktop file '/home/xxx/.config/autostart/skype.desktop' has malformed Icon key 'skype.png'(should not include extension)

file="$HOME/.config/autostart/skype.desktop"

if [ -f "$file" ] ; then
    if `cat "$file" | grep "Icon=" | grep -q ".png"` ; then
        sed -i.bak '/^Icon=/s/\.png$//' "$file"
        cp "$file" "$PWD"
        cp "${file}.bak" "$PWD"     
    else
        echo "Nothing to fix! (maybe fixed already?)"
    fi  
else
    echo "Skype not installed (yet...)"
fi

НАМНОГО изящнее моего оригинала! Единственное, о чем я сожалею, это то, что резервное копирование sed не сохраняет временную метку исходного файла. Но я могу жить с этим.

И, для справки, да, я создал этот скрипт, чтобы исправить реальную "ошибку" в упаковке Skype.

Ответы [ 2 ]

6 голосов
/ 19 февраля 2011

Что-то вроде следующего в sed должно делать то, что вам нужно. Сначала мы проверяем, начинается ли строка с Icon=, а если это так, тогда мы запускаем команду s (т.е. подставляем).

sed -i '/^Icon=/s/\.ico$/.png/' file

Редактировать: Сценарий sed выше также может быть написан так:

/^Icon=/ {             # Only run the following block when this matches
    s/\.ico$/.png/     # Substitute '.ico' at the end of the line with '.png'
}

См. на этой странице для получения дополнительной информации о том, как ограничить выполнение команд.

3 голосов
/ 19 февраля 2011
С 1000 * sed довольно легко справиться.Вот один из способов:
sed 's/^\(Icon=.*\)\.ico$/\1.png/'

По умолчанию sed работает с каждой строкой файла по одной за раз.'S /.../.../' сопоставит регулярное выражение с первым аргументом и заменит его вторым аргументом.\ 1 обозначает все, что соответствует первой группе, которая обозначена круглыми скобками.Вы должны экранировать парены с помощью \.

. Вышеуказанное работает как часть конвейера, но вы можете добавить флаг '-i', например,

sed -i 's/^\(Icon=.*\)\.ico$/\1.png/' input.txt

, чтобы заменитьфайл input.txt на месте.Не добавляйте это, пока не протестируете свой скрипт sed.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...