Как предотвратить объединение нескольких строк вывода из подстановки команд в сценарии BASH?

У меня есть текстовые файлы в нескольких подкаталогах

какой-то/путь/один/файл

какой-то/путь/два/файл

какой-то/путь/три/файл

какой-то/путь/foo/файл

...

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

У меня есть:

SITE=$(grep -w $1 some/path/*/file)

однако это просто создает очень длинную строку, в которой все просто сливается в одну строку.

В идеале эта переменная должна содержать значение * из имени пути в каждой строке:

Например:

какой-то/путь/один/файл

какой-то/путь/три/файл

содержать строку, в которой есть bar.

SITE=$(grep -w bar some/path/*/file)
echo $SITE

должно выглядеть так:

some/path/one/file:this is a line of text that has bar in it
some/path/three/file:this is a line of text that has bar in it

но вместо этого я получаю это:

some/path/one/file:this is a line of text that has bar in it some/path/three/file:this is a line of text that has bar in it

Есть ли способ сделать эту переменную многострочной, чтобы позже я мог делать такие вещи, как:

for i in `echo $SITE`; do
WHATEVER=$(echo $i | cut -d ':' -f 1 | cut -d '/' -f 3)
echo $WHATEVER
done

и иметь вывод:

one
three

Или я иду об этом совершенно неправильно?


person user2773624    schedule 14.03.2014    source источник
comment
вместо захвата вывода из grep, вы не можете просто распечатать вывод из grep в файл? Таким образом, у вас будет одна строка для каждого совпадения, которая будет включать имя файла.   -  person ALiX    schedule 15.03.2014


Ответы (3)


Это не подстановка команды $(), сводящая вывод к одной строке; это echo переменной без кавычек. Если вы сделаете echo "$SITE", вы увидите многострочный вывод.

Сказав это, распространенным подходом к построчному чтению является конструкция while read. Вы можете сделать что-то вроде этого:

while read line; do
    WHATEVER=$(echo "$i" | cut -d ':' -f 1 | cut -d '/' -f 3)
    echo $WHATEVER
done < <(grep -w bar some/path/*/file)

Обратите внимание, что мы можем использовать канал вместо подстановки процесса <() в последней строке, но приведенное выше лучше, если переменные, установленные в цикле while, должны оставаться в области видимости за пределами цикла while.

Конечно, если это все, что вам нужно сделать с выводом, то следующее будет намного проще:

grep -w bar some/path/*/file | cut -d ':' -f 1 | cut -d '/' -f 3
person Digital Trauma    schedule 14.03.2014
comment
Вау... Это была глупая ошибка. Спасибо за while read идею! - person user2773624; 15.03.2014
comment
@user2773624 user2773624 Не глупая ошибка :) Это одна из странных вещей в bash, которая часто сбивает людей с толку. - person Digital Trauma; 15.03.2014

Если это просто для отображения, всегда есть echo -e "$SITE". Параметр -e оставляет все табуляции, пробелы и новые строки на месте. Не забывайте о цитатах.

Если вы хотите обработать каждую строку позже в сценарии, вы можете попробовать следующее:

echo -n "$SITE" | while read line ; do
  echo "$line"
done
person Erik E. Lorenz    schedule 14.03.2014

IFS=$'\r\n' LINES=($(grep -w $1 some/path/*/file))

Это создаст массив строк

Затем вы можете пройтись по массиву и обработать каждую строку отдельно ${LINES[i]}

Подробнее см. здесь https://stackoverflow.com/a/11393884/652904

person nhed    schedule 14.03.2014