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

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

files=""
for f in $(ls ~/Downloads | grep -v ^d)
        do

                files+="$f"","

        done 
        echo "$files"

здесь папка для загрузки содержит файлы, такие как

this: 01 - Agar Mujhse Mohabbat Hai - www.downloadming.com.mp3

Ожидаемый результат: 01 - Agar Mujhse Mohabbat Hai - www.downloadming.com.mp3

Фактический результат: 01, -, Агар, Mujhse, Mohabbat, Hai, -, www.downloadming.com.mp3

Все решения приветствуются.

4
задан 17 March 2017 в 14:17

4 ответа

не анализируют ls

files=()

cd ~/Downloads
for file in *; do
    [[ -d $file ]] && continue
    files+=( "$file" )
done

printf "%s\n" "${files[@]}"

comma_separated=$(IFS=,; echo "${files[*]}")
echo "$comma_separated"

, Как Вы видели, for f in $(ls) выполняет итерации по эти слова в выводе, не эти строки . Сохраните ls для того, когда Вы хотите, чтобы человеческие глаза видели файлы и использовали шаблоны имени файла оболочки, когда Вы хотите, чтобы Ваш сценарий сделал что-то с именами файлов.

0
ответ дан 17 March 2017 в 14:17

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

0
ответ дан 17 March 2017 в 14:17

Использование while read вместо for

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

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

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

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

find ~/Downloads -type f | tr '\n' ','
0
ответ дан 17 March 2017 в 14:17

Это - проблема Внутренний Разделитель полей. Скорее это не проблема, это было разработано тот путь. Это разделяет вход пробелом, так же, как в позиционных параметрах.

Из страницы справочника Bash:

для имени [[в [слово...]];] действительно перечисляют;готово

Список слов после в расширен, генерировав список объектов. Имя переменной определяется к каждому элементу этого списка в свою очередь, и список выполняется каждый раз. Если в слове опущен, для команды выполняет список однажды для каждого позиционного параметра, который устанавливается. Статус возврата является статусом выхода последней команды, которая выполняется. Если расширение объектов после в результатах в пустом списке, никакие команды не выполняются, и статус возврата 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

тогда как 'ls' печатает просто имена файлов:

SomeDirectory
file1
file2
file3
1
ответ дан 17 March 2017 в 14:17

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

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