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

env=$(grep -v -m 1 "#" file)
if [ "$env" != "" ]
then
    sed -i "/\<$env\>/s/^/#/" file
fi
echo $env

Что превращает это:

#this is an example file
this is the first line
this is the second line

В это:

#this is an example file
#this is the first line
this is the second line

И перекликается с этим this is the first line

Я считаю, что есть более простой, канонический способ сделать это, возможно, используя только sed. Было бы удобно, если бы он был однострочным, потому что на самом деле он выполняется по ssh. С другой стороны, выполнение через ssh вызывает проблемы с расширением переменных среды в аргументах sed, и экранирование с помощью \\\$env не работает. Любое предложение приветствуется.

2
Ulrik 30 Май 2014 в 18:32

4 ответа

Лучший ответ

Как вы уже предложили, вы можете использовать только sed:

sed '0,/^[^#]/ s/^[^#].*/#\0/' file.txt

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

1
hek2mgl 30 Май 2014 в 18:55
Без проблем. sed правил! ;)
 – 
hek2mgl
30 Май 2014 в 18:57
Да, но на первый взгляд похоже на клингонский.
 – 
Ulrik
30 Май 2014 в 19:02

Если вы найдете строку с символом #, перейдите к следующей строке. Если следующая строка начинается с символа #, перейдите к следующей строке, иначе добавьте #

sed -e '/#/{:start; n; /^#/b start; s/^/#/}; '  file.txt
1
luis_js 30 Май 2014 в 19:08

Предположим, вы используете пистолет sed:

sed -i '/^[^#]/{s/^/#/;:S;N;bS;}' file

При совпадении с первой строкой без комментариев он добавит # перед строкой и прочитает оставшиеся строки. Так как он будет считывать оставшиеся строки в PatternSpace, если это большой файл и после первой строки, не являющейся комментариями, будет много строк, он будет потреблять большой объем памяти.

Лучший ответ - это luis_js, я все еще пишу здесь свой ответ, просто предлагаю другой способ.

Поскольку упоминается OP, я сохраняю свой первый ответ здесь (но это неверно)

sed '/^#/{n;s/^/#/;}' file

Он рекомендует строки после прокомментированных строк и может прокомментировать первую не прокомментированную строку, только если есть нечетные прокомментированные строки перед первой неоткомментированной строкой.

1
WKPlus 30 Май 2014 в 19:43

Был один ответ, но его удалили. Думаю, стоит упомянуть об этом в образовательных целях:

sed -i '/^#/{n;s/^/#/}' file

Это самый короткий фрагмент кода для этого, НО он комментирует комментарии. (в файле будет "##"). Так что, если кто-то еще не возражает против этого в их конкретном сценарии, это все равно полезно ...

0
Ulrik 30 Май 2014 в 19:11
Это был мой ответ, я обнаружил, что это неправильно. Когда файл сначала содержит две закомментированные строки, он снова прокомментирует вторые комментарии и ничего не сделает с третьей строкой. Это работает только тогда, когда у вас сначала есть нечетные строки комментариев.
 – 
WKPlus
30 Май 2014 в 19:27