Проблема со сценариями Shell и именами файлов заключается в том, что оболочка разбивает входной поток на токены по пробелам и символам новой строки. Какие символы используются, хранится в глобальной переменной IFS
, которая является аббревиатурой для разделителя поля ввода. Проблема в том, что имена файлов могут содержать пробелы и переводы строк. И если вы не правильно указали имена файлов, как это было в вашем вопросе, то имена файлов разделяются оболочкой.
Проблема
Создайте несколько файлов с пробелом:
$ touch a\ {1..3}
Если вы используете шаблон перетаскивания для итерации файлов, все в порядке:
$ for f in a\ *; do echo ►$f◄; done
►a 1◄
►a 2◄
►a 3◄
Но когда вы используете вспомогательную оболочку, которая повторяет имена файлов, они запутываются:
$ for f in $(echo a\ *); do echo ►$f◄; done
►a◄
►1◄
►a◄
►2◄
►a◄
►3◄
То же самое происходит, когда вы используете find
:
$ for f in $(find . -name 'a *'); do echo ►$f◄; done
►./a◄
►2◄
►./a◄
►3◄
►./a◄
►1◄
Решение
Лучший способ прочитать список файлов - это разделить их с помощью символ, которого обычно нет в файле. Это нулевой символ $'\0'
. Программа find
имеет специальное действие под названием -print0
для печати имени файла с завершающим нулевым символом. А функция Bash mapfile
может читать список, который разделен нулевыми символами:
$ mapfile -d $'\0' list < <(find . -name 'a *' -print0)
Теперь вы можете написать функцию, которой нужен список имен файлов.
$ inode() { for f in "$@"; do stat -c %i "$f"; done; }
И передать список имен файлов, правильно указанных в кавычках, для функции.
$ inode "${list[@]}"
2638642
2638644
2638641
И это работает даже с символами новой строки в имени файла.