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

Как Ulrich упомянул в своем комментарии, которым причина состоит в том, что многобайтовые символы всегда считаются частью слова. Они не должны быть указаны в iskeyword. Заключить справку в кавычки :h iskeyword который указывает на :h isfname:

Многобайтовые символы 256 и выше всегда включаются, только символы, до 255 указаны с этой опцией. Для UTF-8 символы 0xa0 к 0xff включены также.

1
05.12.2013, 14:55
2 ответа

Директива for f in $(find .) разделяет список элементов для итерации пространством. В современной оболочке, как zsh, могли использоваться флаги расширения.

for f in "${(@f)$(find .)}" ; do echo "$f" ; done

Пребывание с bash, мы можем работать вокруг этого, любят упомянутый в другом вопросе, изменяющем входной разделитель, символ раньше разделял элементы, временно при присвоении результатов find к переменной. Отключение бахвалящийся в течение времени, будучи предотвращает расширение подстановочных символов, такой как * в них.

set -f  # Disable globbing.
IFS=$(echo -e '\0') files=( $(find .  -print0) )  # Read newline separated files into an array.
for f in ${files[@]}; do echo $f; done
set +f  # Reenable globbing.

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

С другой стороны, xargs может использоваться для передачи путей от find к другой программе. Используя -print0 команда к find и -0 переключатель к xargs, они используют нулевой символ в качестве разделителя. Добавление -n1 к xargs назовите дескрипторы одним именем файла за один раз.

find . -print0 | xargs -0 -n1 echo
1
27.01.2020, 23:38
  • 1
    IFS='\n' в bash? Вы уверены, что это делает то, что Вы хотите? –  manatwork 05.12.2013, 15:14
  • 2
    IFS не должен действительно чиниться со слишком много. Здесь, это просто используется тщательно для той одной строки только для преобразования результата в чистый массив. –  XZS 05.12.2013, 15:15
  • 3
    Попробованный это? Там Вы устанавливаете IFS к двум символам: “\\” и “n”. Так безотносительно find выводы будут разделены на любом из тех двух символов. pastebin.com/kj8PsrKw –  manatwork 05.12.2013, 15:27
  • 4
    я забыл символ расширения. С $'\n' это действительно оценивает к символу новой строки. pastebin.com/3NGSB1n4 –  XZS 05.12.2013, 16:34
  • 5
    for f in "$(find .)", в любой оболочке, выполняет тело цикла точно однажды. В Вашем решении для удара Вы избежали отключать globbing, и необходимо отметить, что это порывает с именами файлов, содержащими новые строки. –  Gilles 'SO- stop being evil' 06.12.2013, 01:07

Вы дважды заключенный в кавычки подстановка переменных в аргументе echo, но не замена команды в итеративном списке for цикл. Это - то, где разделение на пробеле и другой злобности происходит.

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

Если можно предположить, что имена файлов не содержат новые строки, то можно расположить разделить вывод find путем ограничения символов разделителя полей только символом новой строки (для защиты пробелов и вкладок) и выключения globbing (для защиты \[?*).

IFS='
'; set +f
for f in $(find .); do
  unset IFS; set +f
  echo "$f"
done
unset IFS; set +f

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

find . -exec echo {} \;

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

find . -exec sh -c 'echo "$0"' {} \;

Вместо того, чтобы вызвать один экземпляр оболочки на файл, можно сгруппировать вызовы оболочки и цикл по набору файлов. find команда делает группирование и удостоверяется для не осмотра через предел длины командной строки. Не забывайте передавать фиктивный аргумент как $0 так, чтобы файлы были $1 и так далее.

find . -exec sh -c 'for x; do echo "$x"; done' _ {} +

При использовании ksh93, удара или zsh, можно использовать их рекурсивное globbing средство: **/PATTERN поиски подстановочного шаблона в каталоге и его подкаталогах рекурсивно. В ksh93 необходимо работать set -o globstar сначала. В ударе необходимо работать shopt -s globstar во-первых, и остерегайтесь этого ** также рекурсивно вызывает внутренние символьные ссылки на каталоги.

for f in **/*; do
  echo "$f"
done

Zsh также имеет спецификаторы шарика, которые включают в категорию большую часть использования find. Другие оболочки не имеют такой вещи.

1
27.01.2020, 23:38

Теги

Похожие вопросы