Istnieje wspólny wzorzec, w którym są pary plików, z których jedna nazwa pary może być łatwo wyprowadzona z drugiej. Jeśli plik, którego znasz, nazywa się X, a drugi plik to Y, masz następujące typowe przypadki użycia.
- Do zmiany nazwy Y jest X z usuniętym rozszerzeniem i/lub datownikiem dodanym.
- Do transkodowania, Y jest X z innym rozszerzeniem i prawdopodobnie innym katalogiem.
- Dla wielu zadań analizy danych, X i Y dzielą niektóre części nazwy pliku, ale mają inne parametry lub rozszerzenia.
Wszystkie one nadają się do tego samego szkieletu kodu.
for x in path/to/base*.ext; do
dir=${x%/*} # Trim trailing file name, keep dir
base=${x##*/} # Trim any leading directory
# In this case, $y has a different subdirectory and a different extension
y=${dir%/to}/from/${base%.ext}.newext
# Maybe check if y exists? Or doesn't exist?
if [ -e "$y" ]; then
echo "$0: $y already exists -- skipping" >&2
continue
fi
mv or ffmpeg or awk or whatever "$x" and "$y"
done
Kluczem jest tu obserwacja, że y
mogą pochodzić z x
z kilku prostych podstawień zmiennych. Pętlisz wartości x
i obliczasz odpowiadającą im wartość y
w pętli.
Tutaj użyliśmy powłoka wbudowanej ${variable#prefix}
i ${variable%suffix}
operatorów, aby powrócić wartość zmiennej z dowolnego wiodącym prefix
lub końcowe suffix
odpowiednio przycięte off. (Istnieje również ##
i %%
, aby dopasować najdłuższy, zamiast najkrótszego możliwego dopasowania. Wyrażenie po #
lub %
jest zwykłym wzorcem globu powłoki.) Zwykle są to wszystko, czego potrzebujesz, chociaż często widzisz skrypty sed
lub awk
nawet dla tego trywialnego zadania (gdzie naprawdę powinieneś zazwyczaj unikać zewnętrznego procesu), a także oczywiście dla bardziej wymagających transformacji.
Jeśli trzeba pętli ponad x
plików rozrzuconych po różnych katalogach, może pętla powinna rozpocząć się z czymś jak
find dir1 dir2 etc/and/so/forth -type f -name 'x-files*.ext' -print |
while IFS='' read -r x; do
:
powszechnie postrzegane problemu w podobnych pytań jest odpowiedź niespełniające zacytować $x
i $y
poprawnie. Zasadniczo każda zmienna zawierająca nazwę pliku powinna być zawsze podwójnie cytowana.
gdzie X i Y są niezależne, częstym rozwiązaniem jest pętla nad tutaj dokumentu zawierającego mapowanie:
while read -r x y; do
: stuff with "$x" and "$y"
done <<'____HERE'
first_x_value first_y_value
another_x corresponding_y
random surprise
____HERE
Konieczne jest zapętlenie przedrostków i przyrostków, nie pełnych nazw plików. –
Zachowanie, które otrzymujesz, jest takie samo, jak to, co zrobiłaby zagnieżdżona pętla 'for' w * dowolnym * języku; nie ma w tym nic szczególnego. –
Za każdym razem, gdy chcę zrobić coś stosunkowo prostego, jak na przykład powtarzanie par wartości, Bash sprawia, że obciążenie wygląda jak nie do pokonania. Dlatego nie używam bashu, gdy potrzebuję czegoś bardziej skomplikowanego niż lista wywołań powłoki. – ThorSummoner