Как насчет объединения смежных пар строк, а затем использования обратной ссылки для поиска неуникального префикса?
$ sed '$!N; /\(.*\)\n\1:FOO/D; P;D' file
red.7
green.2:FOO
blue.6
yellow.9:FOO
Объяснение:
$!N
- если мы еще не на последней строке, добавляем следующую строку к пробелу шаблона, разделенному новой строкой/\(.*\)\n
- сопоставляем все до новой строки (т.е. первая из каждой пары строк) и сохранить в группу захвата\1:FOO
теперь соответствует всему, что было захвачено из первой строки, а затем :FOO
(\1
является обратной ссылкой на первую группу захвата)/\(. *\)\n\1:FOO/D
- если вторая строка каждой пары такая же, как и первая, за которой следует :FOO
, то D
удалите первуюP
rint и D
удалите оставшуюся строку, готовую начать следующий циклили более аккуратно (спасибо @don_crissti)
sed '$! N; /\(.*\)\n\1:FOO/!P;D' файл'
N
означает, что в пространстве шаблона всегда есть две последовательные строки и sedP
ринтирует первую из них, только если вторая строка не является такая же, как первая, плюс суффикс:FOO
. ЗатемD
удаляет первую удаляет первую строку из пространства шаблона и начинает цикл заново.
Простой сценарий rename-lower
для текущего каталога, если команда rename
не работает, вы можете изменить ее в mv .
#/bin/bash
# script to replace all upper case to lower case
for i in *
do
d=$(echo ${i} |tr [:upper:] [:lower:]);
if [ ${d} != ${i} ]
then
echo "renaming:" ${i} ${d}
rename ${i} ${d} ${i}
# mv ${i} ${d}
fi
done
Пример
$ ls
tmp.EwcM2s6kfU tmp.kcUX6rtjiu tmp.kzpqLvWcnQ tmp.N1H8bLt1at
$ rename-lower
renaming: tmp.EwcM2s6kfU tmp.ewcm2s6kfu
renaming: tmp.kcUX6rtjiu tmp.kcux6rtjiu
renaming: tmp.kzpqLvWcnQ tmp.kzpqlvwcnq
renaming: tmp.N1H8bLt1at tmp.n1h8blt1at
Этот ответ от Alex B из Stack Overflow поможет вам переименовать как файлы, так и подпапки в каталоге.
Он заключается в использовании команд Linux find
и rename
. Я бы только добавил, что команда, указанная в приведенной выше ссылке, также изменит имена каталогов. Если вы хотите изменить только имена файлов, вам нужно изменить параметр -depth
на следующий: -type f
.
Еще одно регулярное выражение, данное команде rename
, может быть приведенным ниже, и я думаю, что его легче понять.
find my_root_dir -type f -execdir rename 'y/A-Z/a-z/' {} \;
Имейте в виду, что между регулярным выражением команды переименовать
и фигурными скобками есть необходимый пробел, а между ними и символом завершения команды \;
Также помните, что он переименует каждый файл не только в каталоге, из которого вы выполняете команду (каталог my_root_dir
), но также и во все файлы в каждой подпапке, содержащейся в этом. Вы можете использовать опцию -maxdepth 0
с командой find
, чтобы заставить ее применять тесты и действия только к самим начальным точкам.
Вот:
for i in $( ls | grep [A-Z] ); do mv -f $i `echo $i | tr 'A-Z' 'a-z'`; done
А это пример, показывающий, как это работает:
X$ ls
123123HHHSK FILE_[1-10] DB
FILE1 FILE_{1-10} SQL
X$ for i in $( ls | grep [A-Z] ); do mv -f $i `echo $i | tr 'A-Z' 'a-z'`; done
X$ ls
123123hhhsk file_[1-10] db
file1 file_{1-10} sql
EDIT: Мы могли бы легко использовать опцию -f
, чтобы избежать использования yes y
.
Ваша команда mv
не работает так, как задумано, потому что происходит расширение подстановочных знаков, и в результате получается один список имен файлов, который передается в mv
. Синтаксис mv
следующий mv SOURCE1 SOURCE2 ... DESTINATION
, т.е. все аргументы, кроме последнего, являются именами файлов, которые должны быть перемещены в место назначения. mv
не поддерживает переименование на основе шаблонов.
Если у вас есть утилита prename
, вы можете использовать ее для переименования файлов, выполняя Perl-код для каждого имени. Синтаксис: prename PERL-CODE FILENAME1 FILENAME2 ...
. Имя файла находится в переменной $_
, а функция lc
преобразует его аргумент в нижний регистр, поэтому можно использовать следующий код:
prename '$_ = lc($_)' /home/imp/hpt/outbound/[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z].[STFWMfWM][OUAHER][0-9]
Если у вас нет этой утилиты, вы можете загрузить версию с CPAN.
В качестве альтернативы, вы можете выполнить переименование в оболочке, используя цикл. В bash вы можете использовать ${x,,}
, чтобы получить значение x
, преобразованное в нижний регистр.
for x in /home/imp/hpt/outbound/[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z].[STFWMfWM][OUAHER][0-9]; do
mv "$x" "${x,,}"
done
С zsh
:
autoload zmv # best in ~/.zshrc
zmv '[[:alnum:]](#c8).[STFWMfWM][OUAHER][0-9]' '${(L)f}'
Это позволит проверить наличие потенциальных конфликтов.
Если вы хотите заменить один класс символов на другой, используйте tr
.
for f in *; do
test -f "$f" && echo mv "$f" "$( tr '[:upper:]' '[:lower:]' <<<"$f" )"
done
Сценарий переименует все файлы в текущем каталоге в строчные буквы. Каталоги будут пропущены. Удалите echo
, когда вы уверены, что оно делает то, что вы хотите. Вы можете заменить [: upper:]
и [: lower:]
на AZ
и az
соответственно, если у вас есть только стандартные имена файлов ASCII. (примечание: AZ
, а не [AZ]
).
В качестве альтернативы можно использовать встроенную в Bash подстановку переменных с верхнего на нижний регистр:
for f in *; do
test -f "$f" && echo mv "$f" "${f,,}"
done
Следующее сработало для меня:
for f in *; do mv -T "$f" "$(echo $f | tr [A-Z] [a-z])"; done
Было бы интересно, какие проблемы с моим решением.