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 {} +

다른 사람이 쓸 수 있는 디렉터리에서는 이 작업을 수행하지 않는 것이 좋습니다 . 이렇게 하면 악의적인 사용자가 파일 시스템에서 임의의 파일 /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

그러나 perls Find::File(GNU와 반대 find)는 안전한 디렉토리 탐색을 수행하지 않으므로 이를 수행하려는 작업도 아닙니다 /tmp.


노트.

¹ 공격자는 /tmp/. /auth.log파일을 생성하고 find파일 찾기와 이동 사이의 심볼릭 링크로 디렉터리를 대체할 수 있습니다 mv(창은 쉽게 임의로 커질 수 있음 ) ."/tmp/. "/var/log/var/log/auth.log/var/log/auth

² 더 나쁜 것은 공격자가 crontab을 이동할 수 있는 /tmp/foo.log악성 crontab코드와 /tmp/foo심볼릭 링크를 생성할 수 있다는 것입니다./etc/cron.d입력하다 /etc/cron.d. 이것은 mv(적어도 적용되고 cp) ln모호함이 있을 수 있는 곳입니다.이동하다그리고이사 오다. GNU mv-t(입력하다) 그리고 -T(도착하다) 옵션.

File::Find³를 실행하여 디렉터리를 트래버스합니다 chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..").... 따라서 누군가 디렉토리를 생성 하고 적절할 /tmp/foo/bar때 이름을 바꿔서 ./tmp/barchdir("../..")/

답변2

다음 줄은 다음과 같습니다.

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

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

관련 정보