Невозможно использовать файлы со специальными символами в оболочке

A (несколько громоздкий) способ сделать это - установить диспетчер обновлений, чтобы обновления не были установлены автоматически, а затем снимите флажок с каждого перечисленного пакета в доступных обновлениях, кроме Chromium.

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

1
задан 17 March 2017 в 15:17

3 ответа

Более короткое решение: find ~/Downloads -type f -not -name "d*" -printf "%f,"

2
ответ дан 24 May 2018 в 08:00
  • 1
    OP использовал grep -v ^d, чтобы избежать списков каталогов, ваш подход пропустит все файлы, начиная с d. Вы хотели find ~/Downloads -type f. – terdon♦ 8 May 2014 в 23:23
  • 2
    @terdon Как ls dirname | grep -v ^d избегать списков каталогов? – Jos 9 May 2014 в 00:58
  • 3
    @terdon dunno you, но в zsh + grep 2.18 + ls 8.21 ls ~/Downloads | grep -v ^d не мешает каталогам. – Braiam 9 May 2014 в 03:34
  • 4
    @Jos Это, конечно, не будет, я полностью неправильно понял. Я думал, что это ls -l, и я прочитал ответ Гленна, который пропускает каталоги, поэтому я предположил. Извини, я виноват. – terdon♦ 9 May 2014 в 04:45
  • 5
    @terdon ОК. Фактически, OP, возможно, попытался пропустить каталоги, начиная с выполнения ls -l, а затем передумал использовать ls и оставил ^d. Но я прочитал его как «пропустить имена файлов, начиная с d». – Jos 9 May 2014 в 11:24

Используйте while read вместо for

. Самый безопасный способ, который я нашел для итерации над списками имен файлов, заключается в том, чтобы направить на while read:

find ~/Downloads -type f | while read filename; do
  echo "found file called $filename";
done

Как вы можете видеть, оно помещает полное имя файла (разделение по строкам вместо пробела) в имя переменной, которое вы указываете, здесь $filename.

Однако из исходного вопроса, если действительно требуется, список файлов, разделенных запятыми, тогда вам даже не нужно итерации, просто используйте tr для перевода разделителей строк в запятую:

find ~/Downloads -type f | tr '\n' ','
1
ответ дан 24 May 2018 в 08:00

Это проблема внутреннего полевого разделителя. Скорее, это не проблема, она была разработана именно так. Он разбивает входные пробелы, как и в позиционных параметрах.

На странице пользователя Bash:

для имени [[в [word ...]]; ] сделать список; done Перечисленный список слов, следующих в, расширяется, генерируя список элементов. Имя переменной по очереди устанавливается в каждый элемент этого списка, и список выполняется каждый раз. Если в слове опущено, команда for выполняет список один раз для каждого установленного параметра позиционирования. Статус возврата - это статус выхода последней выполняемой команды. Если расширение элементов, следующих в результатах в пустом списке, никаких команд не выполняется, а статус возврата равен 0.

Это означает, что он расширяет результаты выражения в список слов. Здесь находится внутренний разделитель полей, $ IFS. По умолчанию для $ IFS задано значение пробела (пробел, табуляция и новая строка). Это означает, что поле состоит из всего, вплоть до (но не включая) этих пробельных символов. Поскольку имена файлов состоят из пробелов, они обрабатывают их как несколько разных полей и запускают цикл один раз для каждого поля. Способ исправить это - настроить значение $ IFS.

Итак, вам нужно настроить $ IFS на что-то другое, кроме пробела. Используя ваш текущий метод, однако не было бы возможности указать, где заканчивается одно имя файла, а другое начинается, если у всех их нет расширения файлов. Более простой способ сделать это можно с помощью утилиты find следующим образом:

#Save the original IFS
oldifs=$IFS
#Set the new IFS to the ASCII null character \x00
IFS=$(echo -ne "\x00")

files="" #To prevent scoping issues

#Use the find utility to find and print just regular files (not directories),
#and not going further than ~/Downloads (remove '-maxlength 1' to make the
#search fully recursive), then print the filenames in the format
#file1\x00file2\x00file3\x00file4...

#However, since our new IFS is now \x00, the boundary upon which these filenames are
#separated now works as expected
for f in $(find ~/Downloads -maxdepth 1 -type f -print0)
do
  files="$files,$f"
done
echo "$files"

#Reset IFS
IFS=$oldifs

Я также хотел бы отметить, что ваше утверждение ls ~/Downloads | grep -v ^d, вероятно, не делает то, что вы ожидаете. Похоже, вы пытались отфильтровать каталоги, но то, что на самом деле происходит здесь, это то, что он отфильтровывает файлы, начинающиеся с 'd'. Это связано с тем, что вы не используете длинную форму ls, например ls -l. ls -l выводит вывод следующим образом:

drwxrwxrw- user group SomeDirectory size date_modified filename

wheras 'ls' печатает только имена файлов:

SomeDirectory
file1
file2
file3
1
ответ дан 24 May 2018 в 08:00
  • 1
    Я думаю, это не то, чего хочет OP. Если я попробую, я получу что-то вроде этого ,/home/user/Pictures/file1/home/user/Pictures/file2/home/user/Pictures/file2 , цикл кажется ненужным, потому что всегда есть только один вывод для всех файлов. – TuKsn 11 May 2014 в 22:40

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

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