시추

시추

표현식의 결과(즉, 명령의 출력)를 변수에 할당하고 이에 대해 작업을 수행하고 싶습니다. 예를 들어 이를 문자열과 연결한 다음 에코합니다. 이것이 내가 얻는 것입니다:

#!/bin/bash
cd ~/Desktop;
thefile= ls -t -U | grep -m 1 "Screen Shot";
echo "Most recent screenshot is: "$thefile;

그러나 이것은 다음과 같이 출력됩니다.

Screen Shot 2011-07-03 at 1.55.43 PM.png
Most recent screenshot is: 

따라서 에 할당되지 않은 것처럼 보이지만 $thefile실행 시 인쇄됩니다.

내가 무엇을 놓치고 있나요?

답변1

쉘 할당은 등호 뒤에 공백이 없는 단어입니다. 그래서 당신이 쓴 것은 null 값을 할당하는 것입니다 thefile. 또한 할당은 명령과 함께 그룹화되므로 thefile환경 변수가 생성되고 할당은 해당 특정 명령에 대해 로컬입니다. 즉, 호출자만 ls할당된 값을 볼 수 있습니다.

명령의 출력을 캡처하려고 하므로 다음을 사용해야 합니다.명령 대체:

thefile=$(ls -t -U | grep -m 1 "Screen Shot")

(일부 문헌에서는 대체 구문을 보여줍니다 thefile=`ls …`. 역따옴표 구문은 때때로 역따옴표 안의 인용이 이상하다는 점을 제외하면 달러 괄호 구문과 동일하므로 그냥 사용하세요 $(…).)

스크립트에 대한 추가 참고사항:

  • -t(시간별로 정렬됨)과 -U(GNU별로 정렬되지 않음 )을 결합하는 ls것은 의미가 없습니다 -t.

  • 일치하는 스크린샷을 사용하는 것보다 와일드카드를 전달 하고 이를 사용하여 첫 번째 파일을 캡처하는 것이 더 깔끔 grep할 것입니다 .lshead

      thefile=$(ls -td -- *"Screen Shot"* | head -n 1)
    
  • 보통 하나출력 구문 분석에 대한 나쁜 아이디어ls. 파일 이름에 인쇄할 수 없는 문자가 포함되어 있으면 크게 실패할 수 있습니다. 그러나 이것이 없으면 날짜별로 파일을 정렬하는 것이 어렵습니다 ls. 따라서 파일 이름에 인쇄할 수 없는 문자나 백슬래시가 없다는 것을 알고 있다면 이것이 허용되는 솔루션입니다.

  • 변수 대체에는 항상 큰따옴표를 사용하십시오.즉, 여기에 쓰세요

      echo "Most recent screenshot is: $thefile"
    

    큰따옴표가 없으면 변수 값이 다시 확장되므로 공백이나 기타 특수 문자가 포함된 경우 문제가 발생할 수 있습니다.

  • 줄 끝에는 세미콜론이 필요하지 않습니다. 중복되지만 무해합니다.

  • 쉘 스크립트에서는 일반적으로 다음을 포함하는 것이 가장 좋습니다.set -e. 이는 명령이 실패하면(0이 아닌 상태를 반환하여) 쉘이 종료되도록 지시합니다.

findGNU 가 있고 sort(특히 내장되지 않은 Linux 또는 Cygwin을 실행하는 경우) 최신 파일을 찾는 또 다른 방법이 있습니다. find파일과 해당 날짜를 나열한 다음 sortand를 사용합니다(여기서는 NUL로 구분된 레코드를 읽는 것으로 가정 read합니다). ) 최신 파일을 추출합니다.bashzsh-d ''

IFS=/ read -rd '' ignored thefile < <(
  find -maxdepth 1 -type f -name "*Screen Shot*" -printf "%T@/%p\0" |
    sort -rnz)

bash 대신 zsh에서 이 스크립트를 작성하려는 경우 zsh에서 최신 파일을 캡처하는 더 쉬운 방법이 있습니다.글로벌 예선이름뿐만 아니라 파일 메타데이터에도 와일드카드 일치가 허용됩니다. (om[1])패턴을 따르는 부분은 glob 한정자입니다. om일치하는 항목은 연령이 증가하는 기준으로 정렬되고(즉, 수정 시간에 따라 최신 항목부터) [1]첫 번째 일치 항목만 추출됩니다. 전체 일치 항목은 기술적으로 배열이기 때문에 괄호 안에 넣어야 합니다. 왜냐하면 globbing은 파일 목록을 반환하기 때문입니다. 이는 [1]이 특정 경우에 목록에 (최대) 하나의 파일이 포함되어 있음을 의미하더라도 마찬가지입니다.

#!/bin/zsh
set -e
cd ~/Desktop
thefile=(*"Screen Shot"*(om[1]))
print -r "Most recent screenshot is: $thefile"

답변2

여러 줄/명령을 사용하여 이 작업을 수행하려면 다음을 수행하세요.

output=$( bash <<EOF
#multiline/multiple command/s
EOF
)

또는:

output=$(
#multiline/multiple command/s
)

예:

#!/bin/bash
output="$( bash <<EOF
echo first
echo second
echo third
EOF
)"
echo "$output"

산출:

first
second
third

답변3

완전성을 위해 다른 셸에서 다음을 수행합니다.

본 쉘

1970년대 후반 Bourne 쉘은 명령 대체를 도입했습니다. 오늘날에는 더 이상 사용되지 않지만 많은 쉘의 구문은 해당 쉘의 구문을 기반으로 합니다.

var=`any shell code`

하위 프로세스에서 해석되면 any shell code출력이 파이프로 이동됩니다. 그 사이에 쉘은 파이프의 다른 쪽 끝에서 출력을 읽고 이를 $var변수에 저장합니다.

하지만 참고하세요모두이 출력의 후행 줄 바꿈은 제거됩니다.

Bourne 쉘은 배열 변수를 지원하지 않지만 다음을 사용하여 명령으로 출력된 단어를 위치 인수( $1, $2...)에 저장할 수 있습니다.

set -- `some code`

또는:

set x `some code`; shift

이전 버전에서는 --지원되지 않습니다 .

, 후행 개행 제거 외에도 의 출력은 --기반 분할 + 와일드카드의 영향을 받습니다 some code. $IFS예를 들어 일부 코드가 를 출력 foo,/*<newline><newline>하고 $IFS포함하는 ,경우 의 숨겨지지 않은 모든 파일이 $1포함되고 나머지 매개변수는 입니다 ./foo/

시추

또한 1970년대 후반부터 1980년대 초반까지 당시 매우 인기가 있었고 tcsh많은 단점에도 불구하고 일부 시스템에서 여전히 살아남았습니다.

set array = `some code`

출력 분할 some code(공백, 탭 또는 개행 기준) 의 결과 단어를 $array목록 변수에 저장합니다.

set array = "`some code`"

개행에서만 분할하는 것을 제외하면 동일합니다(의 요소는 $array출력의 비어 있지 않은 행이 됩니다).

ksh88 및 POSIX와 같은 쉘.

오늘날 sh표준 sh 언어 인터프리터의 하나 이상의 구현은 주로 David Korn이 작성하고 Bourne 쉘에서 일부 수정 및 개선된 쉘의 마지막 진화인 ksh88의 하위 집합을 기반으로 합니다. 여기에는 bash, dash, ksh, yash, mksh, zsh가 포함됩니다(이들 중 다수의 경우 sh 사양 준수는 일부 옵션을 통해 활성화해야 하거나 호출됩니다 sh).

var=$(any shell code)

var=`...`이는 중첩을 더 쉽게 만들고 백슬래시 해석을 엉망으로 만들지 않는다는 점을 제외하면 Bourne 쉘과 유사하게 작동합니다 .

ksh에는 배열이 있지만 POSIX sh 사양에는 배열 지원이 포함되지 않습니다.

rc 및 파생 상품

rc1980년대 후반 Research Unix V10과 plan9의 셸이며, 한때 Unix의 후속 제품이었습니다. 일부 파생물을 생성한 쉘의 공개 도메인 복제본도 있습니다. 적어도 그게 es전부입니다 akanga. 위의 구문보다 훨씬 더 나은 구문이 있었지만 불행히도 실제로는 이해되지 않았습니다.

array = `cmd
array = ` {any shell code}

저장된 출력은 any shell code문자 $ifs로 분할됩니다 $array.

array = `` (chars) {any shell code}

동일합니다. 분할하는 chars대신 지정된 값을 사용 하면 됩니다 $ifs. 를 사용하면 var = ``(){shell code}출력을 분할하지 않고 정확하게 저장할 수 있습니다(실제로 이 작업을 즉시 수행할 수 있는 유일한 셸).

케시

ksh는 1980년대 초에 배열을 도입한 최초의 Bourne 유사 셸이었습니다. 구문은 다음과 같습니다.

set -A array -- $(some code)

Bourne 쉘과 마찬가지로 후행 개행 제거, $IFS-분할 및 와일드카드 작업을 수행합니다.

some command | read var1 var2 var3

출력의 첫 번째 줄을 읽고 some command분할하고 $IFS(그러나 백슬래시를 사용하여 구분 기호와 개행 문자를 이스케이프할 수 있음) 결과를 이러한 변수에 저장하는 데에도 사용할 수 있습니다.

read또한 zsh에서도 작동하지만 서브쉘에서 실행되는 bash, yash 또는 pdksh/mksh와 같은 다른 ksh 유사 쉘에서는 작동하지 않습니다 ( sh표준에서는 발생 여부를 지정하지 않으므로 만들 수 없습니다) 휴대용)을 사용하세요 sh. Bash에서는 shopt -s lastpipe쉘의 비대화식 호출을 용이하게 합니다.

some code | read -A array

첫 번째 줄의 단어가 배열 요소에 저장된다는 점만 제외하면 동일합니다( 옵션은 자체 내장 옵션 으로 bash이름이 변경됩니다 ).-aread

ksh는 또한 공동 프로세스를 도입합니다.

some command |&
IFS= read -r first_line <&p
IFS= read -r second_line <&p

예를 들어, 이는 출력의 첫 번째 및 두 번째 라인을 각 변수로 읽는 데 사용될 수 있습니다 some command.

zsh와 bash는 나중에 다른 구문을 사용하여 공동 프로세스 지원을 추가했습니다.

다루기 힘든

zsh(Bourne과 유사한 또 다른 셸이지만 csh 및 rc 기능도 있음)는 1991년(첫 번째 버전이 전년도에 출시된 지 몇 달 후) 버전 2.0에서 배열 지원을 도입했습니다.

array=( $(some code) )

개행 제거 및 IFS 분할(와일드카드 아님)을 수행하고 결과 단어를 배열 요소에 할당합니다.

이 구문은 나중에 1993년 ksh93과 1996년 bash 2.0에 의해 복사되었지만 ksh88처럼 최상위에 글로빙을 수행했습니다.

$IFS다음 이외의 것들과 분리 zsh:

array=( ${(f)"$(some code)"} ) # split on lineFeed aka newline
array=( ${(0)"$(some code)"} ) # split on NUL
array=( ${(s[string])"$(some code)"} ) # split on any string

zsh또한 변수에 NUL 문자를 저장할 수 있는 유일한 셸이므로 이러한 문자가 포함된 명령의 출력을 차단하지 않는 유일한 셸입니다. NUL은 실제로 $IFSin의 기본값 입니다 zsh(다른 Bourne과 유사한 쉘에서와 마찬가지로 공백, 탭 및 개행 문자는 제외).

some command | IFS= read -rd '' var

some command출력의 첫 번째 NUL 문자까지 저장하는 데 사용할 수 있습니다 $var. NUL은 텍스트에 나타날 수 없으므로 텍스트를 그대로 저장하는 방법입니다. -dksh93에서 -d ''NUL을 구분하는 것은 bash/zsh 추가입니다.

zsh는 또한 임의 개수의 문자 읽기(원래는 키 입력을 읽기 위한 것이지만 읽을 fd를 지정하는 것과 결합하면 임의의 문자에 사용할 수 있음) read와 같은 몇 가지 옵션을 추가했습니다 . 옵션 / 관련 의미가 나중에 추가되었습니다 .-k-uksh93bash-N-n

some command | read -u0 -k10 var

some command출력에 의 처음 10자를 저장합니다 $var.

sysread모듈의 구문을 사용하여 시스템 호출을 위한 원시 인터페이스 zsh/system로 블록의 입력을 읽을 수도 있습니다 .read()

동일한 이름의 모듈에 내장된 기능을 사용하여 zpty의사 터미널 쌍을 통해 명령과 상호 작용할 수도 있으므로 보다 대화형 방식으로 입력을 보내고 출력을 읽을 수 있습니다 expect.

크쉬 93

1993년 후반에 작성자가 발표한 ksh를 완전히 재작성한 이 버전은 bash 2+(그리고 어느 정도 zsh 및 mksh)에 큰 영감을 주었습니다.

var=${
  any shell code
}

var=$(any shell code)이는 서브셸 환경에서 실행되지 않는다는 점을 제외하면 동일합니다 any shell code. 즉, 셸이 동일할 필요가 없고 나중에 환경을 복원하며 수정 사항이 이후에도 그대로 유지되므로 약간 더 효율적이라는 의미입니다.

최신 버전입니다 mksh.

세게 때리다

readarray array < <(some command)

배열 요소에 행 some command(옵션을 사용하여 제거할 수 있는 구분 기호 포함 )을 저장합니다 . 소위 프로세스 교체가 1980년대 중반 ksh에 추가되었지만 처음에는 리디렉션 대상으로 사용할 수 없었습니다(이 문제는 훨씬 나중에 ksh93에서 수정되었습니다).-t$array<(...)

Bash 4.4+에서는 NUL을 포함하여 개행 외에 다른 구분 기호를 사용할 수 있습니다.

readarray -t -d '' array < <(find . -print0)

find예를 들어, 의 출력에서 ​​NUL로 구분된 레코드의 내용을 저장하는 데 사용할 수 있습니다 $array.

다음과 같이 할 수도 있습니다.

read var1 var2 < <(some command)

옵션이 활성화되지 않은 경우에도 작동합니다 lastpipe(zsh에서도 작동함).

야쉬

read var1 var2 <(any shell code)

ksh의 프로세스 교체처럼 보이지만 그 안에 있는 기능은 프로세스 리디렉션이라고 하며 명명된 파이프의 경로로 확장하는 대신 해당 fd(여기서는 0)가 다른 쪽 끝이 연결된 파이프라인에 할당됩니다. 파이프의 읽기 측에 대한 명령입니다.

물고기

구문이 다른 쉘과 상당히 다른 비교적 후발주자입니다(목표는 여전히 변경 중이지만 훨씬 더 나은 경우가 많습니다).

set array (some shell code)

쉘 코드 출력의 각 행을 배열의 요소에 지정하십시오.

some command | read var1 var2

첫 번째 줄은 읽혀지고, 분할 $IFS(변경될 수 있음) 또는 구분 기호 로 -d delim저장되며 . 행의 단어를 배열에 저장합니다.$var1$var2read -a array

some command | read -L var1 var2

다른 변수의 처음 두 행에 대해.

some command | read -z var

첫 번째 NUL 이전의 모든 내용(따라서 텍스트 출력의 모든 내용)은 $var.

관련 정보