Для файлов в каталоге указывается только имя файла (без пути)

99

Как мне повторить только имя файла, если я перебираю каталог с помощью цикла for?

for filename in /home/user/*
do
  echo $filename
done;

вытянет полный путь с именем файла. Мне просто нужно имя файла.

Mechaflash
источник

Ответы:

166

Если вам нужно собственное bashрешение

for file in /home/user/*; do
  echo "${file##*/}"
done

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

Однако могу ли я предложить просто использовать find

find /home/user -type f -printf "%f\n"
SiegeX
источник
9
Хороший ответ. Для тех, кто хочет узнать больше о расширении параметров: wiki.bash-hackers.org/syntax/pe#substring_removal
DougW
1
-printf: unknown primary or operator => unix.stackexchange.com/a/272493/72893
Nobita
2
Рассмотрите возможность перехода ${file##*/}на "${file##*/}"поддержку имен файлов с пробелами, например, «Мое имя файла с пробелами.txt».
WinEunuuchs2Unix
echo "$ {file ## * /}" возвращает пустую строку
Алессандро C
48

Просто используйте basename:

echo `basename "$filename"`

Кавычки необходимы в случае, если $ filename содержит, например, пробелы.

Шон Брайт
источник
3
лучше использовать расширение параметров, не требует обращений к внешним двоичным файлам.
SiegeX
5
Кстати, `` устарело. Лучше использовать, $()как Оли
SiegeX
1
Извините за комментарий к этому старому ответу, но базовое имя не будет работать правильно для файлов с пространством. Пример: PWD выход: /test 1, basename $(pwd)выход: test. Протестировано на OS X и Ubuntu Server (14.04). Нативное решение bash, рекомендованное @SiegeX, - это то, что сработало для меня.
Марко Грешак
@ MarkoGrešak Используйте basename "$(pwd)"вместо этого.
YoungFrog
@YoungFrog благодарит за вклад, но это было 9 месяцев назад. Также было бы лучше использовать переменную $PWDвместо запуска команды.
Марко Грешак
16

Использование basename:

echo $(basename /foo/bar/stuff)
Оливер Чарльзуорт
источник
Почему вы используете echo? basenameуже печатает результаты. echoможет даже исказить результат, если вы не процитируете подоболочку. Пример: echo $(basename path/with\ \ spaces)неправильно печатает with spaces(только один пробел).
Socowi
8

Другой подход - использовать lsпри чтении списка файлов в каталоге, чтобы дать вам то, что вы хотите, то есть «только имя файла / s». В отличие от чтения полного пути к файлу с последующим извлечением компонента «имя файла» в теле цикла for.

Пример ниже, следующий за вашим оригиналом:

for filename in $(ls /home/user/)
do
  echo $filename
done;

Если вы запускаете сценарий в том же каталоге, что и файлы, он просто становится:

for filename in $(ls)
do
  echo $filename
done;
Райан
источник
1
lsвключает любые точечные файлы, которые *обычно не расширяются. Также for f in $(...) ...не работает, если любое имя файла содержит пробелы, если вы не установили IFS, может завершиться ошибкой, если любое имя файла содержит символ glob, если вы не установили -f / -o noglob, и в зависимости от системы или оболочки echoможет завершиться ошибкой, если любое имя файла содержит дефис + букву или обратную косую черту. OTOH ls -1 /path/to/dirсам по себе надежно печатает каждое имя файла в строке по модулю разницы файлов точек.
dave_thompson_085
0

если вам нужно только имя файла:

for file in /home/user/*; do       
  f=$(echo "${file##*/}");
  filename=$(echo $f| cut  -d'.' -f 1); #file has extension, it return only filename
  echo $filename
done

подробнее о cutкоманде см. здесь .

Йозеф
источник