Як отримати лише ім'я файлу за допомогою sed


18

Як я можу отримати лише ім'я файлу за допомогою sed? Я це

out_file=$(echo $in_file|sed "s/\(.*\.\).*/\1mp4/g")

Але я теж отримую шлях /root/video.mp4, і хочу лише video.mp4.

Відповіді:


28

basenameз GNU coreutils можуть допомогти вам виконати цю роботу:

$ basename /root/video.mp4
video.mp4

Якщо ви вже знаєте розширення файлу, ви можете викликати його basenameза допомогою синтаксису basename NAME [SUFFIX], щоб видалити його:

$ basename /root/video.mp4 .mp4
video

Або іншим варіантом буде вирізати все після останньої крапки за допомогою sed:

$ basename /root/video.old.mp4 | sed 's/\.[^.]*$//'
video.old

3
Використовуючи , sed 's/\.[^.]*$//'як у вас є, зазнає невдачі для (прихований) .filenameі .і ..каталоги
Peter.O

9

Найпростіше рішення - видалити все до останньої появи /:

echo /root/video.mp4 | sed 's/.*\///'


5

Використовуйте будь-який із наступних способів:

out_file="${in_file##*/}"

out_file="$(basename $in_file)"

out_file="$(echo $in_file | sed 's=.*/==')"

out_file="$(echo $in_file | awk -F"/" '{ print $NF }')"

пс. Ви отримуєте той самий рядок, оскільки у вашому операторі \(.*\.\)збігається з рядком від початку до точки ( /root/video.), а потім ви вручну додаєте той, .mp4який такий же, як у початковій рядку. Ви повинні використовувати s=.*\([^/]*\)=\1=замість цього.

Оновлення: (Перше виправлено зараз)

Щоб отримати єдине ім’я файлу без розширення, ви можете:

out_file="$(echo $in_file | sed 's=.*/==;s/\.[^.]*$/.new_ext/')"

out_file="$(echo $in_file | sed 's=\([^/]*\)\.[^./]*$=\1.new_ext=')"

out_file="$(echo $in_file | awk -F"/" '{ gsub (/\.[^/.]*$/,".new_ext",$NF);print $NF }'

Але за допомогою будь-якого з цих методів я отримую назву файлу у форматі, і мені потрібно отримати лише ім'я файлу та ввести новий формат вручну.
Шиксони

Ах, це має сенс. Я оновив свою відповідь.
пік

@rush: Будуть крайові регістри, наприклад, для файлу з ім’ям my.file.tar.gz.
доношені успішно

@donothingsуспішно був символ пропуску крапки в останньому sedта awk. Виправлено. Дякую.
пік

4

Однією з основ використання регулярного вираження є те, що шаблони жадібні за характером при вказівці підстановки. Хоча відповідь, запропонована @uloBasEI, безумовно, є робочою відповіддю, вона також вимагає використання команди basename. Оригінальне запитання від @Shixons вимагає рішення, використовуючи лише sed.

Перш ніж продовжувати, завжди корисно знати, яка версія sed є цільовим. Я припускаю, що BSD (в комплекті з OSX).

Перш за все, шаблон, запропонований в оригінальному запитанні, не працює, оскільки він фіксує все від початку вхідного рядка до останньої крапки. Без якоря цей пошук проковтне все зліва направо. Таким чином, узгоджений шаблон "/ 1" - це все, що стосується останньої крапки. Навіть ім’я файлу з декількома крапками проковтнеться цілим. Зовсім не бажаний результат.

Перший крок - це створення стратегії виявлення шаблонів. Тут ви хочете позбутися всього зліва від назви файла (ми розберемося з розширенням пізніше):

out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"

Пошук відповідає з початку рядка. Він відповідає шаблону "/.*" нуля або більше разів і видаляє все згодом. Друкуємо відповідні шаблони за допомогою "\ 1". Ми не шукаємо глобально; ми шукаємо з початку рядка, вказавши ^ якір.

Ми отримуємо кращу чіткість, включаючи параметр "-E", тому нам не потрібно уникати дужок:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"

Отже, тепер у нас є частина зліва. Додамо частину праворуч. Зауважте, що нам потрібно зберігати ліву частину як зразок, оскільки саме так ми можемо вказати, що вона з’являється нульовою чи більше разів. Все, що ми робимо зараз, - це додати шаблон для частини праворуч:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"

Ми друкуємо лише другий збіг, тим самим відкидаючи все, крім назви файлу. Але нам ще потрібно видалити розширення імені файлу.

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"

"$" Наприкінці не є обов'язковим.

Нарешті, щоб додати нове розширення, яке ви просто перегляньте так:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"

Додаткова оптимізація полягає в тому, щоб зробити першу косу рису вперед необов'язковою для обробки відносних шляхів:

out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"

Я натрапив на це питання, ледачи, шукаючи шаблон sed для заміни базового імені . Я працюю над позбавленою системою, на якій не встановлена ​​ця команда.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.