2016-06-20 2 views
1

После поиска в Интернете я был в состоянии понять, как прочитать файл построчно:Чтение и запись построчно в Баш скрипт

while read p; do 
    echo $p 
done < file.txt 

Но я бы на самом деле хотел бы изменить строку в файле , Например:

while read p; do 
    if condition 
    then 
    echo $p | perl -i -pe 's/a/b/' 
    fi 
done < file.txt 

Однако это не реально изменить файл.

+3

все средства обработки текста могут читать файл по строкам и обрабатывать, нет необходимости привлекать петли bash для этого. – karakfa

+1

Согласитесь с @karakfa: Знаете ли вы, что 'sed -i 's/a/b /' file' может обрабатывать весь файл одновременно, намного эффективнее и (очевидно) имеет намного меньше кода? Удачи. – shellter

+0

Если вы хотите отредактировать файл, почему бы вам не использовать редактор? 'ex' и' ed' приходят на ум ... –

ответ

1

Update   далеко лучшая версия Баш кода добавлен. Благодаря Charles Duffy для комментариев.


Ваш Perl один вкладыш занимает линию по трубам в него echo $p |, получая свой стандартный ввод таким образом. Он ничего не делает с самим файлом, поэтому флаг -i не влияет. -p делает печать стандартным потоком вывода. Так что вся строка, echo ..., не касается файла.

Вы можете перенаправить вывод на новый файл, а затем переместить его, чтобы перезаписать file.txt. Вот простой пример, который добавляет каждую строку в новый файл. Для лучшего кода bash см. Обновление ниже.

while read p; do 
    if condition 
    then 
     echo $p | perl -pe 's/a/b/' >> temp_out.txt 
    else 
     echo $p >> temp_out.txt 
    fi 
done < file.txt 
mv temp_out.txt file.txt 

Мы должны добавить else где все неизмененные строки также добавляется. Обратите внимание, что в общем случае мы не можем заменить только некоторые строки, но весь файл должен быть переписан.

Если это все, что сценарий вы можете сделать с помощью очень простой однострочной линии, см. Конец. Если больше работы сделано, вы также можете поместить все это в скрипт Perl, но я полагаю, что могут быть другие веские причины для сценария bash.


Update   Гораздо лучше вариант выше. См read и echo в Builtins in Bash manual

  • прилагая каждую строку открывает файл заново каждый раз без необходимости. Просто переадресовать в конце цикла, как это делается в терминале

  • read использует обратную косую черту для экранирования, удаляя ее из ввода. Выключите это с помощью -r

  • Удаляет пустое пространство, как часть разрыва строки в слова. Подавляйте это, отключая переменную, которая контролирует, какие символы используются для разделения, IFS=

  • echo $p может делать всевозможные непреднамеренные вещи.Форматированная печать лучше, printf '%s\n' "$p", или по крайней мере echo "$p"

С этим

while IFS= read -r p; do 
    if condition 
    then 
     echo "$p" | perl -pe 's/a/b/' 
    else 
     echo "$p" 
    fi 
done <file.txt> temp_out.txt 
mv temp_out.txt file.txt 

Наконец, если единственной целью Perl однострочника были запустить простую замену, то гораздо лучше просто сделать это в самой оболочке, чем иметь конвейер и запустить совершенно новый процесс для каждой строки.

echo "${p//a/b}" 

Благодаря Charles Duffy для поднятия всех этих пунктов в комментариях.


Несколько комментариев на Perl однострочные. См. Документацию по адресу perlrun.

Команда perl -e '...' выполняет любой действующий код Perl между ''. Когда мы добавляем переключатель -n или -p, он также считывает стандартный ввод и выполняет этот код по его строке в то время, когда -p также распечатывает каждую строку после ее обработки. Стандартный ввод может подаваться в него из файла,

perl -pe '...' input.txt 

в этом случае при добавлении -i флага приведет к файлу изменяется на месте. Или вход может быть подключен к нему, например,

echo "input text" | perl -pe '...' 

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


Чтобы внести изменения в данный файл очереди в то время, вам нужно только это в командной строке

perl -i -pe 's/a/b/' file.txt 

Если есть больше работы, чтобы сделать то, что вполне может быть лучше положить его в сценарии, конечно. В этом случае однострочный может быть также командой в сценарии bash, заменяя весь этот код выше (если для обработки строк не требуется некоторая функция, специфичная для bash).

+0

Помещение '>> temp_out.txt' на каждое' echo' ужасно неэффективно - это повторное открытие выходного файла каждый раз, когда вы хотите его записать, вместо того, чтобы просто держать один дескриптор файла открытым для записи для всей операции t. –

+1

Поместите '> temp_out.txt' после' done' в ваш цикл, и вы избежите всех этих операций 'open' и' close'. –

+0

Кроме того, 'echo $ p' является ошибкой.Используйте 'printf '% s \ n'" $ p "' или, по крайней мере, 'echo '$ p" ', хотя последний все равно будет делать такие вещи, как удаление строки, содержащей только' -n', у нее не будет плохие побочные эффекты 'echo $ p', которые заменят строку, содержащую' * 'список файлов в текущем каталоге, заменяют вкладки пробелами и т. д. –

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