2014-08-29 2 views
0

Я пытаюсь найти способ использования переменных и sed для выполнения конкретной текстовой подстановки с использованием изменяющегося входного файла, но только если есть значение, заданное для замены существующей строки на , Нет значения = ничего не делать (вместо удаления существующей строки).Подстановка sed bash только если переменная имеет значение

Пример Substitute.csv содержит 5 строк =

this-has-text 
this-has-text 

this-has-text 
this-has-text 

и file.text имеет одно предложение =

"When trying this I want to be sure that text-this-has is left alone." 

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

Text='text-this-has' 
Change=`sed -n '3p' substitute.csv` 
grep -rl $Text /home/username/file.txt | xargs sed -i "s|$Text|$Change|" 

В конечном итоге

"When trying this I want to be sure that is left alone." 

Но я хотел бы, чтобы он оставался в

"When trying this I want to be sure that text-this-has is left alone." 

Любой способ сказать СЭД «Если я не дам вам ничего нового, ничего не делать»?


Прошу прощения за чрезмерную, плохую привычку. По сути, я хотел бы выполнить, если строка 3 csv-файла имеет значение - замените $ Text на $ Change inline. Если строка пуста, оставьте $ Text как $ Text.

+2

проверить, если '$ Change' пуст, прежде чем перейти к' sed'? – Kent

+0

Ничего себе, вы сделали этот вопрос ПУТЕМ более сложным, чем это должно быть! Все эти вещи о чтении третьей строки из файла и greps, поданных на xargs, совершенно неактуальны и поэтому теряют время, пытаясь понять все это и обманывает очень простой вопрос. –

ответ

4
Text='text-this-has' 
Change=$(sed -n '3p' substitute.csv) 
if [[ -n $Change ]]; then 
    grep -rl $Text /home/username/file.txt | xargs sed -i "s|$Text|$Change|" 
fi 
+0

ref: http://www.gnu.org/software/bash/manual/bashref.html#Bash-Conditional-Expressions –

+0

Пробовал и забыл поставить правильный путь вместо примера пути. Работал отлично. Спасибо :) – user2416772

3

Просто держать его простой и использовать AWK:

awk -v t="$Text" -v c="$Change" 'c!=""{sub(t,c)} {print}' file 

Если вам нужно Inplace редактирования просто использовать GNU AWK с -i inplace.

Учитывая ваше выяснено требование, это, вероятно, то, что вы на самом деле хотите:

awk -v t="$Text" 'NR==FNR{if (NR==3) c=$0; next} c!=""{sub(t,c)} {print}' Substitute.csv file.txt 
+1

О человек ... Я как раз собирался опубликовать это! –

+0

Мне очень нравится простота этого подхода. Я только начинаю знакомство с sed и еще не занялся awk. Я хотел бы заменить текст в строке и перейти к следующей команде. Не могли бы вы привести пример реализации gawk для этого. Я пробовал пару методов, которые, как я думал, были бы правильными, но не повезло. – user2416772

+0

@ user2416772 sed - отличный инструмент для простых замещений на одной строке, но для чего-либо еще вы должны использовать awk. Я не понимаю ваш запрос, хотя, пожалуйста, отредактируйте исходный вопрос, чтобы показать пример ввода и ожидаемый результат для вашего нового требования или принять ответ здесь и опубликовать новый вопрос. –

2

Тестирования ли $Change имеет значение перед запуском в grep и sed, несомненно, является наиболее эффективным решением Баша, хотя я бит скептически относится к дублированию grep и sed; он сохраняет временный файл в случае файлов, которые не содержат целевой строки, но за счет дополнительного сканирования вплоть до соответствия в случае файлов, которые его содержат.

Если вы ищете набрав эффективность, однако, следующее может быть интересно:

find . -name '*.txt' -exec sed -i "s|$Text|${Change:-&}|" {} \; 

Что будет рекурсивно найти все файлы, чьи имена заканчиваются расширением .txt и выполнить команду sed на каждом из них. ${Change:-&} означает «значение $Change, если оно существует и не является пустым, и в противном случае &"; & на замену команды seds означает «согласованный текст», поэтому s|foo|&| заменяет каждое вхождение foo на себя. Это дорогостоящий нет-op, но если ваше время имеет значение больше, чем время вашего процессора, возможно, оно того стоило.

Смежные вопросы