/ / Shell generyczny odpowiednik zamiennika Bash Substring $ {foo / a / b} - bash, shell, find, sh

Powszechny odpowiednik powłoki Shell Bash zastępujący $ {foo / a / b} - bash, shell, find, sh

Czy istnieje niezależna od powłoki równoważność zastąpienia podciągów Bash:

foo=Hello
echo ${foo/o/a} # will output "Hella"

Większość czasu mogę wykorzystać bash więc to nie jest problem, jednak w połączeniu z find -exec to nie działa. Na przykład, aby zmienić nazwę wszystkich .cpp pliki do .c, Chciałbym użyć:

# does not work
find . -name "*.cpp" -exec mv {} {/.cpp$/.c}

Na razie używam:

# does work, but longer
while read file; do
mv "$file" "${file/.cpp$/.c}";
done <<< $(find . -name "*.cpp")

Najlepiej byłoby, gdyby rozwiązanie, które można było wykorzystać w skryptach, było lepsze!

Odpowiedzi:

4 dla odpowiedzi № 1

Za pomocą find i -exec możesz to zrobić:

find . -name "*.cpp" -exec bash -c "f="$1"; mv "$f" "${f/.cpp/.c}"" - "{}" ;

Jednak to się rozwidli bash -c dla każdej nazwy tak używanej xargs lub for taka pętla jest lepsza ze względu na wydajność:

while IFS= read -d "" -r file; do
mv "$file" "${file/.cpp/.c}"
done < <(find . -name "*.cpp" -print0)

1 dla odpowiedzi nr 2

Btw, alternatywa dla używania bash byłoby użyć rename. Jeśli masz fajne wersja rename polecenie, które jest wysyłane wraz z perl możesz to zrobić:

find -name "*.cpp" -exec rename "s/.cpp$/.c/" {} +

Powyższy przykład zakłada, że ​​masz GNU findutils, mając to, nie musisz przekazywać bieżącego katalogu, ponieważ jest to ustawienie domyślne. Jeśli nie masz GNU findutils, musisz go wyraźnie podać:

find . -name "*.cpp" -exec rename "s/.cpp$/.c/" {} +