W przypadku plików w katalogu wyświetla się tylko echo nazwy pliku (bez ścieżki)

99

W jaki sposób mogę wyświetlić tylko nazwę pliku, jeśli iteruję katalog z pętlą for?

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

ściągnie pełną ścieżkę z nazwą pliku. Chcę tylko nazwę pliku.

Mechaflash
źródło

Odpowiedzi:

166

Jeśli chcesz mieć natywne bashrozwiązanie

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

Powyższe wykorzystuje rozszerzenie parametrów, które jest natywne dla powłoki i nie wymaga wywołania zewnętrznego pliku binarnego, takiego jakbasename

Mogę jednak zasugerować użycie find

find /home/user -type f -printf "%f\n"
SiegeX
źródło
9
Dobra odpowiedź. Dla tych, którzy chcą dowiedzieć się więcej o rozszerzaniu parametrów: wiki.bash-hackers.org/syntax/pe#substring_removal
DougW
1
-printf: nieznany główny lub operator => unix.stackexchange.com/a/272493/72893
Nobita
2
Rozważ zmianę ${file##*/}na, "${file##*/}"aby obsługiwać nazwy plików ze spacjami, np. „Moja nazwa pliku ze spacjami.txt”.
WinEunuuchs2Unix
echo "$ {file ## * /}" zwraca pusty ciąg
Alessandro C
48

Po prostu użyj basename:

echo `basename "$filename"`

Cudzysłowy są potrzebne w przypadku, gdy $ filename zawiera np. Spacje.

Sean Bright
źródło
3
lepiej używać rozszerzania parametrów, nie wymaga wywołań zewnętrznych plików binarnych.
SiegeX
5
Btw, `` jest przestarzałe. Lepiej używać $()tak, jak zrobił to Oli
SiegeX
1
Przepraszamy za komentarz do tej starej odpowiedzi, ale basename nie będzie działać poprawnie dla plików ze spacją. Przykład: moc PWD: /test 1, basename $(pwd)Wydajność: test. Przetestowano na OS X i Ubuntu Server (14.04). Natywne rozwiązanie bash, zgodnie z zaleceniami @SiegeX, działa dla mnie.
Marko Grešak
@ MarkoGrešak Użyj basename "$(pwd)"zamiast tego.
YoungFrog
@YoungFrog dzięki za wkład, ale to było 9 miesięcy temu. Byłoby też lepiej użyć zmiennej $PWDzamiast uruchamiać polecenie.
Marko Grešak
16

Zastosowanie basename:

echo $(basename /foo/bar/stuff)
Oliver Charlesworth
źródło
Dlaczego używasz echo? basenamejuż drukuje wyniki. echomoże nawet zmienić wynik, jeśli nie zacytujesz podpowłoki. Przykład: echo $(basename path/with\ \ spaces)niepoprawne drukowanie with spaces(tylko jedna spacja).
Socowi
8

Innym podejściem jest użycie lspodczas czytania listy plików w katalogu, aby uzyskać to, czego chcesz, tj. „Tylko nazwy plików”. W przeciwieństwie do odczytywania pełnej ścieżki pliku, a następnie wyodrębniania składnika „nazwa pliku” w treści pętli for.

Poniższy przykład zgodny z oryginałem:

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

Jeśli uruchamiasz skrypt w tym samym katalogu, w którym znajdują się pliki, staje się on po prostu:

for filename in $(ls)
do
  echo $filename
done;
ryan
źródło
1
lszawiera wszystkie pliki dotfile, których *rozszerzenie zwykle nie obejmuje. for f in $(...) ...Niepowodzenie również, jeśli jakakolwiek nazwa pliku zawiera białe znaki, chyba że ustawisz IFS, może się nie powieść, jeśli jakakolwiek nazwa pliku zawiera znak globalny, chyba że ustawisz -f / -o noglob, aw zależności od systemu lub powłoki echomoże się nie powieść, jeśli nazwa pliku jest łącznikiem + litera lub zawiera ukośnik odwrotny. OTOH ls -1 /path/to/dirsam z siebie niezawodnie drukuje każdą nazwę pliku w linii, modulo różnicę plików dot.
dave_thompson_085
0

jeśli chcesz tylko nazwę pliku:

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

Więcej informacji na temat cutpolecenia można znaleźć tutaj .

josef
źródło