Cum se elimină extensia numelui de fișier dintr-o listă de nume de fișiere din bash

Încerc să elimin extensia numelui de fișier dintr-o listă de fișiere pe care le-am generat cu următoarele script 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[@]}" 

Această extindere elimină extensia de la intrarea ultima din listă, dar nu una dintre cele anterioare.

De exemplu, doresc următoarea listă:

 file1.pdf file2.pdf file3.png 

A deveni

 file1 file2 file3 

Dar în schimb obțin:

 file1.pdf file2.pdf file3 

Aș prefera să nu fac asta într-o buclă, aș dori să folosesc extinderea parametrilor. Vreau să evit tăierea, deoarece doresc să elimin doar ultima extensie din fișier.

Există un număr destul de mare de subiecte despre extinderea parametrilor și se pare că bash s-ar putea sufoca pe find” folosirea de linii noi … Nu sunt sigur. Dacă un alt subiect preexistent explică această problemă, nu înțeleg pe deplin ce se întâmplă.

Subiecte care par legate, dar parcă nu-mi rezolvă problema:

Comentarii

  • Titlul dvs. menționează matrici, dar nu există nicio matrice în cod.
  • @Kusalananda Vă mulțumim! Am ' am realizat asta de când am cerut. Încă învăț 🙂
  • @Kusalananda Am ' am continuat și am modificat întrebarea pentru a se potrivi mai bine cu problema. Acest lucru ar trebui să împiedice căutările Google eronate să lovească pagina. Vă mulțumim pentru informații!

Răspuns

Puteți face totul dintr-o singură comandă.

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

Comentarii

  • Mulțumesc! De fapt, trebuie să creez câteva copii ale tabloului, unul pentru un meniu care are numele de fișier modificat și unul care va păstra valoarea indexului original, astfel încât să pot apela fișierul din meniu. Este cu adevărat uimitor cât de mult poate face bash! Abilitatea de a încorpora totul într-o singură comandă încă mă suflă! : D

Răspuns

Cred că ați dori să creați o matrice în loc de un șir:

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

Sau cu bash 4.4+, fără a se rupe pe căile de fișiere cu caractere newline:

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

Apoi, extinderea parametrilor dvs. ar trebui să funcționeze, deși aici ar avea mai mult sens să folosiți din nou o variabilă matrice:

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

În exemplul de cod, creați un șir apoi cereți extinderea parametrilor pentru a elimina totul după caracterul punctului final din șirul complet.

Comentarii

  • Vă mulțumim! Îl voi testa de îndată ce am lovit biroul meu dimineața.
  • Aceasta presupune că niciun nume de fișier din acel director nu conține spații albe sau caractere globulare.
  • @Wildcard adresată de ultima editare.
  • @Wildcard Vă mulțumim pentru pointer! ' generez fișierele care sunt aruncate în acest director programatic, deci nu ar trebui să ' să fie o problemă.

Răspuns

Codul dvs. nu include matrici. De asemenea, pune o listă de nume de fișiere într-un șir, $file_list. Conținutul șirului se va termina cu file3.png, iar înlocuirea parametrilor dvs. elimină .png din șir, lăsându-vă un singur șir de nume de fișiere unde ultimul nume de fișier nu are un sufix de nume de fișier.

Punerea mai multor obiecte separate (nume de cale) într-un singur șir descalifică automat scriptul pentru a funcționa corect pentru fișierele ale căror nume conțin spații (sau orice delimitator folosește șirul). Utilizarea unui tablou nu ar ajuta, deoarece ați împărți în continuare ieșirea find pe spații albe.


Pentru a tăia extensia tuturor fișierelor obișnuite ale fișierelor obișnuite în sau sub directorul curent:

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

Acesta caută fișiere obișnuite ale căror nume conțin cel puțin un punct. Numele de cale ale acestor fișiere sunt introduse în loturi într-un script shell mic care se află peste ele. Scriptul shell redenumește fișierele eliminând ultimul punct din numele fișierului și tot ce vine după. Comanda mv actuală este comentată pentru siguranță.

Comanda find acționează ca un generator de căi pentru script shell intern și ni se garantează procesarea corectă a căilor de acces care conțin spații, linii noi și file. Nu este nevoie să stocați ieșirea comenzilor în variabile.

Dacă aveți o matrice de nume de drumuri, posibil create utilizând

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

Atunci veți putea genera numele de cale fără sufixe cu

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

Dacă acest lucru te-ar ajuta, nu știu. Dacă vrei să folosești numele de cale fără sufixe pentru ceva , apoi utilizarea rezultatului comenzii printf de mai sus ar fi greșit de făcut (ați reveni la a nu mai manipula din nou calea ciudată). Deci, atunci când și modul în care ștergeți sufixele numelui fișierului depinde de ceea ce doriți să faceți cu rezultatul.

În legătură:

Comentarii

  • Vă mulțumim! Stăpânirea ta despre bash este foarte evidentă! ' încă mai răzuiesc la suprafață … Vă mulțumim că ați acordat timp pentru ajutor 🙂

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *