2015-04-28 3 views
0

У меня есть много текстовых файлов, в которых я хотел бы найти слово «CASE» и заменить его соответствующим именем файла. Я попыталсяНайдите слово в текстовом файле и замените его на filename

find . -type f | while read file 
do 
awk '{gsub(/CASE/,print "FILENAME",$0)}' $file >$file.$$ 
mv $file.$$ >$file 
done 

, но я получил следующее сообщение об ошибке

AWK: ошибка синтаксиса в исходной строке 1 контекст >>> {GSUB (/ CASE /, печать < < < "ДЕЛО", $ 0)}
AWK: незаконное заявление в исходной строке 1

Я также попытался

получает пустой выход и

AWK: ошибка синтаксиса в исходной строке 1 контекста >>> {GSUB (/ CASE/$ {< < <
AWK: незаконное заявление в исходной строки 1

+1

Никогда не делайте 'для i в $ (ls *)', поскольку это ничего не добавляет по сравнению с 'for i in *' и вводит возможные ошибки, такие как файлы с пробелами в их именах. Кроме того, awk не является оболочкой - вы не можете получить доступ к переменной оболочки внутри awk-скрипта, так же как вы не можете получить доступ к переменной оболочки внутри программы C. См. Http://cfajohnson.com/shell/cus-faq-2.html#Q24 о том, как передать VALUE переменной оболочки в awk-скрипт. –

ответ

2

Почему awk? sed является то, что вы хотите:

while read -r file; do 
    sed -i "s/CASE/${file##*/}/g" "$file" 
done < <(find . -type f) 

или

while read -r file; do 
    sed -i.bak "s/CASE/${file##*/}/g" "$file" 
done < <(find . -type f) 

Чтобы создать резервную копию оригинала.

+0

Я бы, скорее всего, исправлю результат поиска, а не переменную, но . –

+1

Я уверен, что вы хотели бы проверить [это] (http://stackoverflow.com/q/29613304/171318) :) – hek2mgl

+0

О, это хороший момент. –

2

Вы не размещать какие-либо входные выборки и ожидаемые результаты, так что это предположение, но, возможно, это то, что вы хотите:

find . -type f | 
while IFS= read -r file 
do 
    awk '{gsub(/CASE/,FILENAME)} 1' "$file" > "${file}.$$" && 
    mv "${file}.$$" "$file" 
done 

Каждое изменение, которое я сделал в коде оболочки важно, так что если вы не» Понимаете, почему я изменил какую-либо его часть, задайте вопрос.

Кстати, если после внесения изменений вы все еще получаете сообщение об ошибке:

awk: syntax error at source line 1 
awk: illegal statement at source line 1 

, то вы используете старый, сломанный AWK (/ USR/бен/AWK на Solaris). Никогда не используйте этот awk. В Solaris используйте/usr/xpg4/bin/awk (или nawk, если нужно).

Предостережения: вышеуказанное не будет выполнено, если ваше имя файла содержит символы новой строки или амперсанды (&) или экранированные цифры (например, \1). См. Is it possible to escape regex metacharacters reliably with sed. Если какой-либо из этих проблем является проблемой, опубликуйте некоторые репрезентативные примеры ввода и ожидаемый результат.

+1

Я уверен, что вы хотели бы проверить [this] (http://stackoverflow.com/q/29613304/171318) :) – hek2mgl

+1

@ hek2mgl Я добавил ссылка, thx. –

1

print в этом первом скрипте является ошибкой.

Второй аргумент gsub - это строка замены, а не команда.

Вы хотите только FILENAME. (Примечание не "FILENAME" это буквальная строка. FILENAME переменная.)

find . -type f -print0 | while IFS= read -d '' file 
do 
    awk '{gsub(/CASE/,FILENAME,$0)} 7' "$file" >"$file.$$" 
    mv "$file.$$" "$file" 
done 

Обратите внимание, что я цитировал все переменные и фиксированные ваш find | read трубопровод правильно работает для файлов с нечетными символов в названиях (см Bash FAQ 001 для более об этом). Я также исправил ошибочный > в команде mv.

См. Ответы на вопрос this question о том, как правильно удалить исходное имя файла, чтобы сделать его безопасным для использования в заменяемой части gsub.

Также обратите внимание, что последние версии (4.1+, я считаю) awk имеют аргумент -i inplace.

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

for i in *; do awk '{gsub(/CASE/,"'"${i}"'",$0)}' "${i}" > file.txt; done 

Обратите внимание, что я избавилась от более чем бесполезно использования ls (хуже, чем бесполезно, потому что он активно ломает файлы с пробелами или метасимволами в их названиях (см Parsing ls подробнее об этом).

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

for i in *; do awk -v fname="$i" '{gsub(/CASE/,fname,$0)}' "${i}" > file.txt; done 

так, что будет работать с именами файлов с двойными кавычками/и т.д. I n их имена правильно, тогда как версия с прямым изменением переменных не будет.

При этом исправленный первый скрипт является правильным ответом.

+0

'/ CASE /," $ {i} ", $ 0' не будет работать так, как вы получите буквенную строку' $ {i} '. Вместо этого вам понадобится что-то вроде '/ CASE /, ''" $ i "'", $ 0', но я бы не сделал этого, поскольку он все еще открыт для коварного поломки. Кроме того, '$ 0' является третьим аргументом по умолчанию для' * sub() ', поэтому вам не нужно его указывать. –

+0

@ EdMorton Point. Я предположил, что там есть двойные кавычки. Закрепление. –

+1

@EtanReisner Я уверен, что вы хотели бы проверить [это] (http://stackoverflow.com/q/29613304/171318) :) (Извините, для публикации его три раза. Я просто хотел быть справедливым) – hek2mgl

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