Jak usunąć rozszerzenie nazwy pliku z listy nazw plików w bash

Próbuję usunąć rozszerzenie nazwy pliku z listy plików, które wygenerowałem za pomocą następującego skrypt 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[@]}" 

To rozszerzenie odcina rozszerzenie z ostatniego wpisu na liście, ale nie żadnego z wcześniejszych.

Na przykład chcę mieć następującą listę:

 file1.pdf file2.pdf file3.png 

Aby zostać

 file1 file2 file3 

Ale zamiast tego otrzymuję:

 file1.pdf file2.pdf file3 

Wolałbym nie robić tego w pętli, chciałbym używać rozwijania parametrów. Chcę uniknąć cięcia, ponieważ chcę usunąć tylko ostatnie rozszerzenie w pliku.

Jest wiele tematów dotyczących rozszerzania parametrów i wygląda na to, że bash może się dusić na find” użycie nowych linii … Naprawdę nie jestem pewien. Jeśli inny z istniejących wcześniej tematów wyjaśnia ten problem, nie rozumiem w pełni, co się dzieje.

Tematy, które się pojawiają powiązane, ale nie wydają się rozwiązywać mojego problemu:

Komentarze

  • Twój tytuł wspomina o tablicach, ale w kodzie nie ma tablicy.
  • @Kusalananda Dziękuję! ' zdałem sobie z tego sprawę, odkąd o to zapytałem. Wciąż się uczę 🙂
  • @Kusalananda ' poszedłem dalej i zmodyfikowałem pytanie, aby dokładniej odpowiadało problemowi. Powinno to zapobiec trafianiu na stronę przez błędne wyszukiwania Google. Dziękuję za informację!

Odpowiedź

Wszystko można było zrobić jednym poleceniem.

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

Komentarze

  • Dziękuję! Właściwie muszę utworzyć kilka kopii tablicy, jedną dla menu ze zmodyfikowaną nazwą pliku i taką, która zachowa pierwotną wartość indeksu, aby móc wywołać plik z menu. To naprawdę niesamowite, ile bash może zdziałać! Możliwość osadzenia wszystkiego w jednym poleceniu wciąż mnie powala! : D

Odpowiedź

Uważam, że wolałbyś utworzyć tablicę zamiast ciągu:

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

Lub z bash 4.4+, bez przerywania ścieżek plików ze znakami nowej linii:

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

Wtedy rozwinięcie parametrów powinno zadziałać, chociaż w tym przypadku bardziej sensowne byłoby ponowne użycie zmiennej tablicowej:

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

W przykładowym kodzie tworzysz ciąg następnie prosząc rozwinięcie parametrów o usunięcie wszystkiego po ostatnim znaku kropki w pełnym ciągu.

Komentarze

  • Dziękuję! Przetestuję to, gdy tylko dotrę rano do biurka.
  • Zakłada się, że żadne nazwy plików w tym katalogu nie zawierają białych znaków ani znaków globalnych.
  • @Wildcard powinno być rozwiązane w najnowszej edycji.
  • @Wildcard Dzięki za wskaźnik! Ja ' m generuję pliki, które są wrzucane do tego katalogu programowo, więc nie powinno to ' być problemem.

Odpowiedź

Twój kod nie zawiera żadnych tablic. Ponadto umieszcza listę nazw plików w łańcuchu $file_list. Treść ciągu kończy się na file3.png, a podstawienie parametru usuwa .png z ciągu, pozostawiając pojedynczy ciąg nazw plików, gdzie ostatnia nazwa pliku nie ma sufiksu nazwy pliku.

Umieszczenie wielu oddzielnych obiektów (nazw ścieżek) w jednym ciągu automatycznie dyskwalifikuje skrypt z poprawnego działania dla plików, których nazwy zawierają spacje (lub jakikolwiek separator użyty w ciągu). Używanie tablicy nie pomogłoby, ponieważ nadal dzieliłbyś wynik find na białe znaki.


Aby przyciąć rozszerzenie ze wszystkich nazw plików zwykłych plików w bieżącym katalogu lub poniżej:

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 {} + 

Szuka zwykłych plików, których nazwa zawiera co najmniej jedną kropkę. Ścieżki do tych plików są wprowadzane partiami do małego skryptu powłoki, który przetwarza je w pętli. Skrypt powłoki zmienia nazwy plików, usuwając ostatnią kropkę w nazwie pliku i wszystko, co nastąpi później. Faktyczne polecenie mv jest dla bezpieczeństwa zakomentowane.

Polecenie find działa jako generator nazw ścieżek dla wewnętrzny skrypt powłoki i gwarantujemy prawidłowe przetwarzanie ścieżek zawierających spacje, znaki nowej linii i tabulatory. Nie ma potrzeby przechowywania wyników poleceń w zmiennych.

Jeśli masz tablicę nazw ścieżek, prawdopodobnie utworzoną za pomocą

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

Wtedy możesz wypisać nazwy ścieżek bez sufiksów z

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

Czy to ci pomogło, nie wiem. Jeśli chcesz użyć nazw ścieżek bez sufiksów do czegoś , wówczas użycie wyniku powyższego polecenia printf byłoby niewłaściwym rozwiązaniem (nie musiałbyś ponownie zajmować się dziwną nazwą ścieżki). a sposób usunięcia sufiksów nazw plików zależy od tego, co chciałbyś zrobić z wynikiem.

Powiązane:

Komentarze

  • Dziękuję! Twoje opanowanie bash jest bardzo oczywiste! ' nadal skrobię powierzchnię … Dziękuję za poświęcenie czasu na pomoc 🙂

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *