Intereting Posts
Как заставить определенную версию Java? Ошибка компиляции исходного кода, возможно, связанного с cpp Как перенаправить вывод из приложения командной строки (интерпретатор howie AIML) в другое приложение командной строки (espeak)? Что не так с экранированной новой строкой в ​​этой команде sed? Не удается установить раздел Veracrypt на Linux Mint (метаданные хранятся в кеше Windows) Как удалить все, кроме последнего вхождения строки? Как не переключаться за край панелей в tmux Отсутствует список сети в меню после использования airmon-ng Предотвращение завершения работы с использованием сценария оболочки при завершении работы У Solaris есть эквивалент /etc/ld.so.conf? Меню Firefox «3 бара» не открывается rm -rf все файлы и все скрытые файлы. & .. ошибка Как вручную обновить libc6? Содержимое конвейера с несколькими пробелами Как использовать драйверы слияния Git с Jenkins

Как удалить расширение имени файла из списка имен файлов в bash

Я пытаюсь удалить расширение имени файла из списка файлов, созданных мной, с помощью следующего скрипта bash:

#!/bin/bash file_list=$(find . -type f) #assuming that the files are stored in the same directory trimmed_file_list=$(printf '%s\n' "${file_list[@]%.*}") printf '%s\n' "${trimmed_file_list[@]}" 

Это расширение удаляет расширение из последней записи в списке, но не из предыдущих.

Например, я хочу следующий список:

  file1.pdf file2.pdf file3.png 

Становиться

  file1 file2 file3 

Но вместо этого я получаю:

  file1.pdf file2.pdf file3 

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

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

Темы, которые кажутся связанными, но не решают мою проблему:

  • Как я могу удалить расширение имени файла в сценарии оболочки?
  • Расширение параметров оболочки на массивах
  • Удаление расширений файлов с помощью find -exec

Вы можете сделать все в одной команде.

 find /path/to -type f -execdir bash -c 'printf "%s\n" "${@%.*}"' bash {} + 

Ваш код не содержит никаких массивов. Кроме того, он помещает список имен файлов в строку, $file_list . Содержимое строки заканчивается на file3.png а подстановка вашего параметра удаляет .png из строки, оставляя вас с единственной строкой имен файлов, где последнее имя файла не имеет суффикса имени файла.

Помещение нескольких отдельных объектов (путей) в одну строку автоматически лишает скрипт возможности работать должным образом для файлов, имена которых содержат пробелы (или любой другой разделитель, используемый строкой). Использование массива не поможет, так как вы все равно разделите выходные данные find на пробельные символы.


Чтобы обрезать расширение всех имен файлов обычных файлов в текущем каталоге или ниже:

 find . -type f -name "*.*" -exec sh -c ' for pathname do printf "Would move %s to %s...\n" "$pathname" "${pathname%.*}" # mv -i "$pathname" "${pathname%.*}" done' sh {} + 

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

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

Если у вас есть массив путей, возможно, созданный с помощью

 shopt -s globstar nullglob file_list=( **/*.* ) # get pathnames of files with dots in their names 

Тогда вы сможете выводить пути без суффиксов с

 printf '%s\n' "${file_list[@]%.*}" 

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

Связанные с:

  • Понимание опции -exec `find`
  • Почему зацикливание на выводе find плохо работает?

Я полагаю, что вы хотели бы сделать массив вместо строки:

 IFS=$'\n' # split on newline only set -o noglob # disable the glob part file_list=($(find . -name '*.*' -type f)) 

Или с bash 4.4+, не нарушая пути к файлам с символами новой строки:

 readarray -td '' file_list < <(find . -name '*.*' -type f -print0) 

Тогда ваше расширение параметра должно работать, хотя здесь было бы более разумно снова использовать переменную массива:

 trimmed_file_list=("${file_list[@]%.*}") 

В своем примере кода вы создаете строку, а затем запрашиваете расширение параметра удалить все после последнего точечного символа в полной строке.