Поскольку bash завершает работу после завершения команды, вы можете вызвать другой экземпляр bash
после своей команды, чтобы получить интерактивную оболочку:
gnome-terminal --tab -e "bash -c 'ps -ef; bash'" --tab -e "bash -c 'ls; bash'" --tab -e "bash -c 'top -n 1; bash'"
Рассмотрите возможность использования последовательности команд sed
для преобразования начального имени файла в конечное имя файла, а затем выполнения однойmv
для фактического переименования файла:
for i in *%*
do
printf "mv -v '%s' '%s'\n" "$i" \
"$( sed -e 's/%20/ /g' \
-e 's/%28/(/g' \
<<< "$i" )"
done
Этот список команд на самом деле не изменяет ваши файлы, и это хорошо. Он просто выводит команды mv
, которые вы можете использовать, чтобы сделать то, что вы пытаетесь сделать.
Давайте создадим несколько примеров файлов, содержащих %20
и %28
вхождения:
$ for i in foo bar farkle
> do
> touch $i"%20".txt; touch $i"%28".txt; touch $i"%20-%28".txt
> done
$ ls -1
bar%20-%28.txt
bar%20.txt
bar%28.txt
farkle%20-%28.txt
farkle%20.txt
farkle%28.txt
foo%20-%28.txt
foo%20.txt
foo%28.txt
Теперь запустим приведенный в начале список команд:
$ for i in *%*
> do
> printf "mv -v '%s' '%s'\n" "$i" \
> "$(sed -e 's/%20/ /g' -e 's/%28/(/g' <<< "$i")"
> done
mv -v 'bar%20-%28.txt' 'bar -(.txt'
mv -v 'bar%20.txt' 'bar.txt'
mv -v 'bar%28.txt' 'bar(.txt'
mv -v 'farkle%20-%28.txt' 'farkle -(.txt'
mv -v 'farkle%20.txt' 'farkle.txt'
mv -v 'farkle%28.txt' 'farkle(.txt'
mv -v 'foo%20-%28.txt' 'foo -(.txt'
mv -v 'foo%20.txt' 'foo.txt'
mv -v 'foo%28.txt' 'foo(.txt'
Если эта последовательность команд mv
кажется вам правильной, нажмите стрелку вверх -, чтобы запустить команду еще раз, но на этот раз добавьте | sh
в конце, чтобы фактически выполнить эти команды mv
вместо отображения их.
find. -type f -name '*%*' -execdir bash -c '
name=$1
name=${name//%20/ } # replace each %20 by a space
name=${name//%28/(} # replace each %28 by a (
mv "$1" "$name"' bash {} \;
Используется find
для поиска любого обычного файла в текущем каталоге или ниже него, имя которого содержит символ %
. Для каждого такого файла выполняется короткий сценарий bash
, который выполняет две замены, указанные вами в данном имени файла, а затем переименовывает файл.
Было бы легко добавить к этому другие подстановки параметров, чтобы удалить или изменить другие строки в именах файлов.
Возможно, более быстрым способом было бы написать простой цикл, чтобы сделать то же самое, (предполагая оболочку bash
для этого конкретного варианта):
shopt -s nullglob dotglob globstar
for pathname in./**/*%*; do
# skip pathnames to non-regular (or links to non-regular) files
[[ ! -f "$pathname" ]] && continue
name=${pathname##*/} # strip off directory components
name=${name//%20/ } #... so that we don't accidentally
name=${name//%28/(} #... modify the directory path
# the destination is made up by the directory path
# (original pathname with filename stripped off)
# followed by the new name
mv "$pathname" "${pathname%/*}/$name"
done
Параметр оболочки nullglob
заставляет шаблон ./**/*%*
расширяться до ничего если он ничему не соответствует (он обычно остается нераскрытым ), dotglob
позволяет подстановку шаблонов для сопоставления скрытых имен, а globstar
позволяет использовать **
для "рекурсивного" сопоставления с подкаталогами.
Адаптация этого второго цикла к чему-то, что использует find
для генерации имен путей, а не шаблона подстановки (, например. для работы с bash
выпусками до выпуска 4, в котором не было**
):
find. -type f -name '*%*' -exec bash -c '
for pathname do
name=${pathname##*/} # strip off directory components
name=${name//%20/ } #... so that we don't accidentally
name=${name//%28/(} #... modify the directory path
# the destination is made up by the directory path
# (original pathname with filename stripped off)
# followed by the new name
mv "$pathname" "${pathname%/*}/$name"
done' bash {} +
Похоже, что по своей сути это упражнение в декодировании URL, что является чем-то вроде решенной проблемы.
Сохраните это как, скажем,rename_script.sh
:
DECODED="$(awk -niord '{printf RT?$0chr("0x"substr(RT,2)):$0}' RS=%.. <<< "${1}")"
[ ! -f "${1}" ] && echo "Source not found" && exit 1
[ -f "${DECODED}" ] && echo "Target already exists" && exit 1
[ "${1}" != "${DECODED}" ] && mv -i "${1}" "${DECODED}" || echo "Nothing to do"
И призывать таким образом:
find -name "*%*" -print0 | xargs -n1 -0./rename_script.sh
Большой кредит этому ответу :https://stackoverflow.com/a/14000368/2858703