Переименуйте файл и сохраните расширение в bash

#bash #shell

#bash #оболочка

Вопрос:

Я должен переименовать некоторые файлы, которые я точно не знаю, где они находятся, и сохранить их расширения.

Пример: файловая система-2.1.3.war, system-2.1.3.ear, system-2.1.3.ejb в system.ear, system.war, system.ejb

Итак, я написал это.

 find /DIR1 -name "*.ear" -o -name "*.war" -o -name "*.ejb"  
-exec bash -c 'export var1={}; cp $var1 NEW_NAME${var1: -4}' ;
  

Проблема в том, что это работает только для последнего файла в списке «или» команды «найти». Итак, если файл system-2.1.3.ejb, работает, для system-2.1.3.war и system-2.1.3.ear — нет.

Если я изменю find на

 find /DIR1 -name "*.ejb" -o -name "*.war" -o -name "*.ear"
  

Обратите внимание, что *.ear теперь является последним, он будет работать для system-2.1.3.ear, а не для остальных и так далее.

Пожалуйста, помогите мне это исправить.

Я знаю, что могу создать скрипт для выполнения этого, но мне нужен код «в одну строку».

Ответ №1:

Вместо того, чтобы встраивать {} в скрипт, передайте его в качестве аргумента:

 find /DIR1 ( -name "*.ear" -o -name "*.war" -o -name "*.ejb" )  
  -exec sh -c 'ext=${1##*.}; cp "$1" "NEW_NAME.$ext"' _ '{}' ;
  

Без (...) группировки, -exec применяется только к основному, с которым оно неявно «и»отредактировано, предыдущему.

Вы также можете ограничить количество вызовов командной оболочки, перебирая несколько аргументов:

 find /DIR1 ( ... ) -exec sh -c 'for f; do ext=${f##*.}; cp "$f" "NEW_NAME.$ext"; done' _ {}  
  

Комментарии:

1. Я добавляю (an) в свой код и работает, спасибо. Но зачем вы используете «_ ‘{}'», если cp «$ 1» «NEW_NAME.$ ext» уже выполняет эту работу?

2. Аргумент для -c — это скрипт для выполнения, но вам все равно нужно передать аргументы для $1 расширения до. Это упрощает проверку правильности кавычек любых аргументов, передаваемых cp .

Ответ №2:

попробуйте это;

 find /DIR1  ( -name "*.ear" -o -name "*.war"  -o -name "*.ejb" ) -exec bash -c 'export var1={}; cp $var1 NEW_NAME${var1: -4}' ;
  

или

 find ./DIR1/  -regex  '.*(.ear|.war|.ejb)$' -exec bash -c 'export var1={}; cp $var1 NEW_NAME${var1: -4}' ;
  

Например;

 user@host $ ls -arlt DIR1/
total 76
-rw-rw-r--  1 user user     0 Oct 21 22:59 system-2.1.3.war
-rw-rw-r--  1 user user     0 Oct 21 22:59 system-2.1.3.ear
-rw-rw-r--  1 user user     0 Oct 21 22:59 system-2.1.3.ejb
drwxrwxr-x  2 user user  4096 Oct 21 22:59 .


user@host $ find . ( -name "*.ear" -o -name "*.war"  -o -name "*.ejb" ) -exec bash -c 'export var1={}; cp $var1 NEW_NAME${var1: -4}' ;

user@host $ ls -ralt
total 76
-rw-rw-r--  1 user user     0 Oct 21 22:59 system-2.1.3.war
-rw-rw-r--  1 user user     0 Oct 21 22:59 system-2.1.3.ear
-rw-rw-r--  1 user user     0 Oct 21 22:59 system-2.1.3.ejb
drwxrwxrwt 11 root   root   69632 Oct 21 23:10 ..
-rw-rw-r--  1 user user     0 Oct 21 23:10 NEW_NAME.war
-rw-rw-r--  1 user user     0 Oct 21 23:10 NEW_NAME.ear
-rw-rw-r--  1 user user     0 Oct 21 23:10 NEW_NAME.ejb
drwxrwxr-x  2 user user  4096 Oct 21 23:10 .
  

Ответ №3:

Если у вас есть rename утилита, то вы можете избежать разветвления подпроцесса BASH для каждого файла, а также использовать функцию регулярных выражений в, find чтобы избежать множества -name опций:

 find /DIR1 -regextype awk -regex '.*.([we]ar|ejb)$' 
    -exec rename 's/.*(.[^.] )$/system$1/' '{}'  
  

Ответ №4:

Я бы использовал while :

 find . -name "*.war" -o -name "*.ejb" -o -name "*.ear" | while read file; do cp $file NEW_NAME${file: -4}; done
  

Имейте в виду, что и этот, и ваш пример копируют файлы в текущий каталог, поэтому, если у вас в дереве более одного *.war , *.ejb или *.ear , в целевом каталоге останется только последний (ы).