Чтение пути к файлам в виде строки в сценарии оболочки

Моя цель -> Список файлов из команды должен читаться построчно и использоваться как часть другой команды.

Описание -> Команда в linux возвращает

archive/Crow.java
archive/Kaka.java
mypmdhook.sh

который хранится в changed_files переменная. Я использую следующий цикл while для чтения файлов построчно и использую его как часть команды pmd

while read each_file
do
        echo "Inside Loop --  $each_file"
done<$changed_files

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

mypmdhook.sh: 7: mypmdhook.sh: cannot open archive/Crow.java
archive/Kaka.java
mypmdhook.sh: No such file

Можете ли вы сказать мне, как я могу просто получить значение в виде строки, а не в виде файла, который открывается. Между прочим, файл существует, что заставило меня чувствовать себя еще более запутанным (и позже использовать его внутри команды). Я был бы рад любому ответу, который поможет мне понять и решить эту проблему.

3 ответа

Решение

Здесь происходит то, что значение вашей переменной $changed_files подставляется в вашу команду, и вы получаете что-то вроде

while read each_file
do
        echo "Inside Loop -- $each_file"
done < archive/Crow.java 
archive/Kaka.java
mypmdhook.sh

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

Дело в том, что перенаправления (например, <, >, >>) в большинстве случаев принимают имена файлов, но на самом деле вам нужно передать содержимое переменной в stdin. Самый очевидный способ сделать это

echo $changed_files | while read each_file; do echo "Inside Loop -- $each_file"; done

Вы также можете использовать for цикл вместо while read:

for each_file in $changed_files; do echo "inside Loop -- $each_file"; done

Я предпочитаю использовать while read ... если есть вероятность, что какое-то имя файла может содержать пробелы, но в большинстве случаев for ... in будет работать на вас.

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

changed_files="archive/Crow.java
archive/Kaka.java
mypmdhook.sh"
while read each_file
do
        echo "Inside Loop --  $each_file"
done <<< "$changed_files"
Inside Loop --  archive/Crow.java
Inside Loop --  archive/Kaka.java
Inside Loop --  mypmdhook.sh

Чрезвычайно важно процитировать "$changed_files" чтобы сохранить переводы строк, цикл while-read работает так, как вы ожидаете. Практическое правило: всегда заключайте в кавычки переменные, если вы не знаете точно, почему вы хотите оставить кавычки выключенными

Вместо того, чтобы хранить выходные данные команды в переменной использования while цикл как это:

mycommand | while read -r each_file; do echo "Inside Loop -- $each_file"; done

Если вы используете BASH, вы можете использовать process substitution:

while read -r each_file; do echo "Inside Loop -- $each_file"; done < <(mycommand)

кстати ваша попытка done<$changed_files будет предполагать, что changed_files представляет файл.

Другие вопросы по тегам