find -exec에서 {} 반환 문자열을 조작합니다.

find -exec에서 {} 반환 문자열을 조작합니다.

파일이 많을 경우를 대비하여 최대한 효율적으로 수행하고 싶습니다. 내가 원하는 것은 내가 찾은 모든 파일의 이름을 바꾸고 해당 접미사를 제거하는 것입니다.

예를 들어:

[/tmp] $ ls -l
a.log
b.log
c.tmp
[/tmp] $ find /tmp -name "*.log" -type f -exec mv {} {%.*} \;
[/tmp] $ ls -l
a
b
c.tmp

이것은 작동하지 않습니다. 일반적인 bash 변수 ${var%.*}라면 var마지막 ..

답변1

쉘 매개변수 확장 연산자를 사용하려면 쉘을 시작하십시오.

find ~/tmp -name '*.log' -type f -exec sh -c '
  for file do
    mv -i -- "$file" "${file%.*}"
  done' sh {} +

악의적인 사용자가 파일 시스템 1에서 /tmp임의의 파일 이름을 바꾸거나 파일을 임의의 디렉터리 ²로 이동할 수 있으므로 다른 사람이 쓸 수 있는 디렉터리 에서는 그렇게 하고 싶지 않습니다 ..log

일부 구현을 사용하면 find다음 을 mv사용하여 보다 안전하게 만들 수 find -execdir있습니다 mv -T.

find /tmp -name '*.log' -type f -execdir sh -c '
  for file do
    mv -Ti -- "$file" "${file%.*}"
  done' sh {} +

또는 시스템 호출만 수행하여 파일을 다른 파일 시스템이나 디렉토리로 이동하려고 시도하지 않는 rename(perl 변형)을 사용하십시오.rename()

find /tmp -name '*.log' -type f -execdir rename 's/\.log$//' {} +

아니면 다음에서 모든 작업을 수행하세요 perl.

perl -MFile::Find -le '
  find(
    sub {
      if (/\.log\z/) {
        $old = $_;
        s/\.log\z//;
        rename($old, $_) or warn "rename $old->$_: $!\n"
      }
    }, @ARGV)' ~/tmp

그러나 (GNU와는 반대로 ) perl은 안전한 디렉토리 탐색을 수행하지 않으므로 둘 중 하나를 수행하고 싶지 않습니다 .Find::Filefind/tmp


노트.

¹ 공격자는 파일을 생성할 수 있으며 파일을 찾아서 이동하는 /tmp/. /auth.log사이에 (해당 창은 쉽게 임의로 크게 만들 수 있음) 디렉토리를 심볼릭 링크로 교체하여 다음 과 같이 이름이 변경 됩니다 .findmv"/tmp/. "/var/log/var/log/auth.log/var/log/auth

² 훨씬 더 나쁜 것은 공격자가 /tmp/foo.log악의적인 crontab예를 들어 /tmp/foo심볼릭 링크를 생성하여 /etc/cron.d해당 crontab을 이동하게 할 수 있다는 것입니다.~ 안으로 /etc/cron.d. 그것은 둘 다일 수 있는 ( 적어도 mv적용되며 ) 모호합니다 .cpln이동하다그리고이사하다. GNU 는 mv(-t~ 안으로) 그리고 -T(에게) 옵션.

³는 File::Find다음을 수행하여 디렉토리를 탐색합니다 chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..").... 따라서 누군가 디렉토리를 생성 /tmp/foo/bar하고 적절한 순간에 이름을 변경 /tmp/bar하여 .chdir("../..")/

답변2

다음은 한 줄의 내용입니다.

find /tmp -name "*.log" -type f -exec sh -c 'f="{}"; mv "$f" "${f%.*}"' \;

셸을 시작하고, 셸 내부의 적절한 변수에 {}를 할당한 다음, 셸 구문을 사용하여 문자열 조작을 적용합니다.

관련 정보