'{} \;'은(는) 무슨 뜻인가요? 'find' 명령 컨텍스트에서 의미하는 것은 무엇입니까?

'{} \;'은(는) 무슨 뜻인가요? 'find' 명령 컨텍스트에서 의미하는 것은 무엇입니까?

. size = 0​그래서 나는 다음을 시도했습니다.

find ./ -size 0 | xargs rm

하지만 이름이 공백으로 시작하는 파일에서는 문제가 있습니다.

인터넷에서 검색해 보니 이런 내용이 있었습니다.

find ./ -size 0 -exec rm -i {} \;

효과가있다. 하지만 xargs그러기엔 제 사용 방식이 너무 정교한 것 같아요 .

무슨 {} \;뜻인가요?

누군가 나에게 설명해 줄 수 있습니까?

제 영어 실력이 별로 좋지 않으니 간단한 글쓰기를 이용해주세요.

답변1

{}에는 전혀 의미가 없으므로 bash실행된 명령에 대한 인수로 수정되지 않은 채 전달됩니다(여기서는 ) find.

반면에, ;에는 특별한 의미가 있습니다 bash. 일반적으로 동일한 명령줄에 있는 순차적 명령을 구분하는 데 사용됩니다. 여기서 백슬래시 in은 \;세미콜론이 에 의해 명령 구분 기호로 해석되는 것을 방지 bash하고 기본 명령인 에 대한 매개 변수로 전달되도록 하는 데 정확하게 사용됩니다 find. 세미콜론(예: ";"또는 ) 을 인용하면 ';'처리되지 않은 상태로 유지되는 또 다른 방법일 수 있습니다.

명령:

find ./ -size 0 -exec rm -i {} \;

의미: 현재 디렉터리에서 크기가 0인 모든 항목을 찾고 발견된 각 개체에 대해 명령을 실행합니다. 즉, 제거하려는 경우 각 파일에 대해 대화식으로 프롬프트를 표시합니다 /. 그것. 실행된 명령에서 발견된 각 파일 이름으로 대체됩니다. 한 가지 좋은 기능은 이 파일 이름이 파일 이름에 관계없이(포함된 공백, 탭, 줄 바꿈 및 모든 문자 포함) 엄격하게 단일 인수라는 것입니다. 휴대용 해킹이 사용되지 않는 한 이는 의 경우에는 해당되지 않습니다 . 마지막은 절을 끝내기 위해 존재합니다 . 끝을 구분해야 하는 이유는 거의 수행되지 않지만 다른 옵션이 뒤따를 수 있기 때문입니다. 예:.rm -i name{}xargs;-execfind-exec

find . -name "*.js" -exec ls -l {} \; -name "special*" -exec wc -l {} \;

이 명령의 한 가지 문제는 일반 파일이 아닌 파일을 무시하지 않으므로 사용자에게 소켓, 블록 및 문자 장치, 파이프 및 디렉터리를 삭제하라는 메시지를 표시할 수 있다는 것입니다. 예라고 대답하더라도 후자에서는 항상 실패합니다.

여기서는 그다지 중요하지 않지만 또 다른 문제는 rm크기가 0인 각 파일에 대해 호출된다는 것입니다. 끝 을 -exec에서 로 대체하면 에서는 가능한 최소한의 횟수(종종 한 번) 만 호출하여 하위 프로세스 생성을 최적화합니다 ./;+findrm

이 명령을 수정하는 방법은 다음과 같습니다.

find . -type f -size 0 -exec rm -i {} +

답변2

find -exec를 사용하면 {}검색된 각 결과로 확장됩니다.

example예를 들어, 3개의 파일과 가 포함된 a.txt디렉토리 가 있는 경우 다음 b.txt으로 c.txt확장 find example/ -exec rm -i {} \;됩니다.

find example/ -exec rm -i example/a.txt \;
find example/ -exec rm -i example/b.txt \;
find example/ -exec rm -i example/c.txt \;

끝에는 실행 패턴의 끝을 나타내기 위해 \;간단하게 이스케이프됩니다 . ;그렇지 않으면 쉘 자체에서 해석됩니다.

답변3

find명령 exec옵션 과 함께 해당 {}부분은 명령이 실행될 때 발견된 파일 이름으로 대체됩니다. \;실행 중인 명령의 끝을 정의하는 것이므로 중요합니다 .

예를 들어

find ~ -name \*.bak -exec -rm -f {} \;

.bak사용자의 홈 디렉토리나 그 안에 포함된 폴더에서 끝나는 모든 파일을 삭제합니다 . rm -f발견된 각 파일을 실행합니다 .

xargs일반적으로 파이프에서 표준 입력 라인을 가져와 사용자가 제공한 명령을 실행할 때 파이프에서 인수의 꼬리 부분을 형성합니다.

답변4

이것은 오래된 질문이지만 더 많은 정보를 추가하고 싶습니다.

find ./ -size 0 -exec rm -i {} \;

이전 명령에서 the는 \;이스케이프된 세미콜론입니다. 이는 명령이 쉘에 의해 처리되는 것을 방지합니다(즉, 일반적으로 ;명령을 분리합니다).

인수 -exec는 모든 것을 이스케이프된 세미콜론까지 명령으로 해석합니다 \;(즉, rm -i {}에 의해 실행되는 내부 명령이 됩니다 find). 내부 명령 내에서 {}매개변수 확장을 나타냅니다. Pain 영어로 말하면 "여기에 찾은 파일 이름을 삽입하세요"라는 뜻입니다.

따라서 발견된 파일이 "file-a.txt" 및 "file-b.txt" 이면 find실행됩니다 .rm -i file-a.txtrm -i file-b.txt

이 명령의 한 가지 문제는 일반 파일이 아닌 파일을 무시하지 않으므로 사용자에게 소켓, 블록 및 문자 장치, 파이프 및 디렉터리를 삭제하라는 메시지를 표시할 수 있다는 것입니다. 예라고 대답하더라도 후자에서는 항상 실패합니다(즉, 디렉토리를 재귀적으로 삭제해야 함).

여기서는 그다지 중요하지 않지만 또 다른 문제는 rm크기가 0인 각 파일에 대해 호출된다는 것입니다. -exec끝을 from /;으로 대체하면 find는 가능한 최소한의 횟수, 종종 한 번만 +호출하여 하위 프로세스 생성을 최적화합니다 .rm

이 명령을 수정하는 방법은 다음과 같습니다.

find ./ -type f -size 0 -exec rm -i {} +

curly brackets또는 braces: {}다른 방식으로 사용될 수 있습니다.

버팀대 확장

중괄호를 사용하여 시퀀스를 만들 수 있습니다.

### prints out the numbers from 0 to 10
echo {0..10}

## prints out the same numbers, but in reverse order
echo {10..0}

## prints every second number, from 10 to 0
echo {10..0..2}

## prints every second letter, from z and working its way backwards to a.
echo {z..a..2}

또한 두 개 이상의 시퀀스를 결합할 수도 있습니다.

## prints out a pair of letters, from aa to zz.
echo {a..z}{a..z}

접두사 및 접미사 추가:

### adds '"' as prefix and suffix
echo \"{These,words,are,quoted}\"
# output: "These" "words" "are" "quoted"

# concatenates the files file1, file2, and file3 into combined_file.
cat {file1,file2,file3} > combined_file

# copies "file22.txt" to "file22.backup"
cp file22.{txt,backup}

메모:

{...}공백이 없으면 중괄호 안에 공백이 허용되지 않습니다.인용됨또는탈출하다.

echo {file1,file2}\ :{\ A," B",' C'}
# output: file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C

확장된 버팀대 확장.

중괄호를 사용하여 배열을 만들 수 있습니다. Bash의 배열은 ()다음과 같이 괄호 사이에 요소를 넣고 공백을 사용하여 각 요소를 구분하는 방식 으로 정의됩니다 .

month=("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")

배열 내의 요소에 액세스하려면 대괄호 안에 해당 인덱스를 사용합니다 [].

 # Array indexes start at [0], so [3] points to the fourth item
$ echo ${month[3]}
## output: Apr

따라서 다음과 같은 배열을 만들 수 있습니다.

## builds an array that contains all the 2-letter combinations of the entire alphabet.
letter_combos=({a..z}{a..z})

## contains all the binary numbers for an 8-bit register, in ascending order,
## from 00000000, 00000001, 00000010, etc., to 11111111. 
dec2bin=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})

이 마지막 것은 특히 흥미롭습니다. 왜냐하면 이제 dec2bin을 사용하여 8비트 10진수-2진수 변환기를 구축할 수 있기 때문입니다. 이진수로 25가 무엇인지 알고 싶다고 가정해 보겠습니다. 다음을 수행할 수 있습니다.

$ echo ${dec2bin[25]}
## output: 00011001

하지만 Teo는 10진수를 2진수로 변환하는 더 좋은 방법이 없을까요?

  • 예, 있습니다. 하지만 여전히 흥미롭습니다. 그렇죠?

그룹화 명령

{ ... }현재 쉘 컨텍스트에서 실행할 명령 목록을 배치하는 데 사용할 수 있습니다. 아니요서브쉘생성됩니다. 다음 목록은 세미콜론 ;(또는 개행)입니다.필수의.

괄호는 ()명령을 실행하는 데 사용됩니다.서브쉘:

menu_type=bar
echo $menu_type
## output: bar

## new lets called in a sub-shell
(menu_type=superbar; echo $menu_type)
## output: superbar

## back to the context
echo $menu_type
## output: bar

superbar의 새로운 값에 접근할 수 없습니다 menu_type.

그러나 다음과 같이 실행하면:

{ menu_type=superbar; echo $menu_type; }
## output: superbar

echo $menu_type
## output: superbar

{ ... }하위 셸을 생성하지 않으므로 값에 액세스할 수 있습니다 menu_type.

{ ... }라고도 하며 inline group사실상 익명 함수(예: 이름 없는 함수)를 생성합니다. 일반 영어에서는 "표준" 함수와 달리 a 내부의 변수가 { ... }스크립트의 나머지 부분에 계속 표시됩니다.

또한 { ... }여러 명령의 출력을 그룹화 stdout하거나 해당 로 리디렉션을 수신하는 데 사용할 수 있습니다 stdin. 예를 살펴보겠습니다:

#!/bin/bash
# rpm-check.sh
#  Queries an rpm file for description, listing, and whether it can be installed.
#  Saves output to a file.

SUCCESS=0
E_NOARGS=65

if [ -z "$1" ]; then
  echo "Usage: `basename $0` rpm-file"
  exit $E_NOARGS
fi  

{ # Begin command group.
  echo
  echo "Archive Description:"
  rpm -qpi $1       # Query description.
  echo
  echo "Archive Listing:"
  rpm -qpl $1       # Query listing.
  echo
  rpm -i --test $1  # Query whether rpm file can be installed.
  if [ "$?" -eq $SUCCESS ]
  then
    echo "$1 can be installed."
  else
    echo "$1 cannot be installed."
  fi  
  echo              # End command group.
} > "$1.test"       # Redirects output of everything in block to file.

echo "Results of rpm test in file $1.test"

exit 0

이제 그룹의 I/O 리디렉션을 진행하는 방법을 살펴보겠습니다 stdin.

#!/bin/bash
File=/etc/fstab

## reads the first two lines of the file
{
  read line1
  read line2
} < $File

echo "First line in $File is:"
echo "$line1"
echo
echo "Second line in $File is:"
echo "$line2"

exit 0

명령 그룹의 출력을 파일에 저장하는 또 다른 예

## exec commands sequentially and redirects the output of the ls command into the png-list.txt file
echo "I found all these png files:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls > png-list.txt

## exec commands sequentially and redirects the output of the group into the png-list.txt file
{ echo "I found all these png files:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls; } > png-list.txt

차이점이 뭐예요, 테오?

글쎄, 젊은 파다완. 두 번째는 png-list.txt라인으로 시작하여 명령 출력 “I found all these png files:“으로 끝나는 모든 출력이 포함된 파일을 생성합니다 ls.

서브쉘 해킹

Bash는 다음을 위한 하위 쉘을 만듭니다.{ ... }Bash는 중괄호 그룹 명령만약에 그리고 만약에이는 파이프라인의 일부입니다. 예를 들면 다음과 같습니다.

$ { A=1; { A=2; sleep 2; } ; echo $A; }
## output: 2

$ { A=1; { A=2; sleep 2; } | sleep 1; echo $A; }
## output: 1

메모:

중괄호와 그 안에 포함된 명령 목록 사이에는 공백이 있습니다. 그 이유는 {및가 }예약어(즉, 셸에 내장된 명령)이기 때문입니다. 또한 명령 목록은 세미콜론으로 끝나 ;거나 개행 문자를 사용하여 명령을 구분해야 합니다.

매개변수 확장

알겠습니다. 다시 돌아가겠습니다.

month=("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")
echo ${month[3]}
## output: Apr

여기서 중괄호는 {}시퀀스 빌더와 별도로 사용되지 않고 매개변수 확장을 생성하는 방법으로 사용됩니다. 매개변수 확장에는 상자에 표시된 내용이 포함됩니다.

중괄호 안의 변수나 표현식을 가져와서 그것이 나타내는 모든 것으로 확장합니다.

테오 이게 무슨 뜻이에요?

글쎄, 그것은 ${...}쉘이 그 안에 무엇이든지 확장하도록 지시한다는 것을 의미합니다. 이 경우 month이전에 정의한 배열은 다음과 같습니다.

month=("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")

그리고 3배열 내의 항목은 다음을 가리킵니다 "Apr"(즉, Bash 배열의 첫 번째 인덱스는 입니다 [0]). 이는 echo ${month[3]}확장 후 가 echo 로 변환됨을 의미합니다 "Apr".

변수를 값으로 해석하는 것은 변수를 확장하는 한 가지 방법이지만 활용할 수 있는 몇 가지 방법이 더 있습니다. 매개변수 확장을 사용하여 변수에서 읽은 내용을 조작할 수 있습니다(예: 끝 부분을 잘라내는 방식).

다음과 같은 변수가 있다고 가정합니다.

a="This sentence is too longgg"

## chops off the last two gs
echo ${a%gg}
## output: This sentence is too long

이는 파일을 한 형식에서 다른 형식으로 변환하는 데 유용할 수 있습니다. 예를 들어, JPEG 이미지를 가져 image.jpg와서 PNG 이미지로 변환하는 명령이 있는 경우 다음과 같습니다 image.png.

convert image.jpg image.png

다음과 같이 다시 작성할 수 있습니다.

i='image.jpg'
## chops off the extension 'jpg' and adds 'png'
convert $i "${i%jpg}png"
## output: convert image.jpg image.png

하지만 파일 이름만 쓰는 것보다 이것이 어떻게 더 유용할 수 있을까요?

수백 개의 JPEG 이미지가 포함된 디렉토리가 있는 경우 PNG로 변환해야 하며 그 안에서 다음을 실행하면 됩니다.

for i in *.jpg; do convert $i ${i%jpg}png; done

… 그러면 모든 사진이 자동으로 변환됩니다. 환영받는 젊은 파다완입니다.

변수의 시작 부분부터 청크를 잘라내야 하는 경우 대신 다음을 %사용하세요 #.

$ a="Hello World!"

## chops off the word 'Hello' and adds 'Goodbye'
$ echo Goodbye${a#Hello}
## output: Goodbye World!

텍스트 자리 표시자

이후에 사용됩니다 xargs -i(즉, 문자열 교체 옵션). 이중 {}중괄호는 출력 텍스트를 위한 자리 표시자입니다.

## Execute 'echo ./<file>' for each file in the directory
ls . | xargs -i -t echo ./{} $1
#            ^^         ^^

경로명

경로 이름은 전체 경로를 포함하는 파일 이름입니다. 예로서, /home/<user>/Notes/todo.txt. 이를 절대 경로라고도 합니다. 우리 는 {}주로 find. -exec <command> \;그러나 이것은 쉘 내장이 아닙니다. <command>가 포함된 경우 {}find는 를 선택한 파일의 전체 경로 이름으로 대체합니다 "{}".

# Removes all core dump files from user's home directory.
find ~/ -name 'core*' -exec rm {} \;

관련 정보