Чтение пути к файлам в виде строки в сценарии оболочки
Моя цель -> Список файлов из команды должен читаться построчно и использоваться как часть другой команды.
Описание -> Команда в 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
представляет файл.