ls 행과 일치하는 항목이 없으면 스크립트를 종료하십시오.

ls 행과 일치하는 항목이 없으면 스크립트를 종료하십시오.

나는 다음 줄을 포함하는 이 스크립트를 작성 중입니다.

ls -lrt /dir1/dir2/filename*.txt | tail -1 | awk '{print $9}' | read variable

내가 원하는 것은 일치하는 항목이 없으면 if 문을 사용하지 않고 스크립트를 종료하는 것입니다.

답변1

이 명령을 작성하는 방법

이 특정 작업에는 파이프라인이 필요하지 않습니다.

zsh에서:

a=(/dir1/dir2/filename*.txt(Nom[1]))
if ((! #a)); then
  echo >&2 "No file matches /dir1/dir2/filename*.txt"
  exit 2
fi
variable=$a[1]

또는 glob이 일치하지 않으면 자동으로 스크립트를 종료합니다.

set -e
a=(/dir1/dir2/filename*.txt(om[1]))
variable=$a[1]

다른 셸에는 최신 파일을 찾는 기능이 내장되어 있지 않습니다. 파일 이름에 개행 문자를 제외한 인쇄 가능한 문자만 포함된 경우 호출은 ls합리적이지만 해당 옵션을 전달하지 않은 -l다음 이름을 제외한 모든 문자를 구문 분석합니다. 이는 불필요하게 복잡하고 부서지기 쉽습니다(특히 공백 인터럽트). 또한 sort 의 마지막 항목을 -t가져오는 것보다 빠른 sort 의 첫 번째 항목을 가져옵니다 -tr. 직접 방법:

variable=$(ls -td /dir1/dir2/filename*.txt 2>/dev/null | head -n 1)
if [ -z "$variable" ]; then
  echo >&2 "No file matches /dir1/dir2/filename*.txt"
  exit 2
fi

처리 파이프라인

파이프의 왼쪽이 실패할 때(즉, 0이 아닌 상태로 종료되거나 신호로 인해 종료되는 경우) 스크립트를 중단하려면 ksh93 및 bash에서 옵션을 설정 pipefail하고 파이프 상태를 0이 아닌 상태로 만들 수 있습니다.

set -e -o pipefail
somecommand | filter
echo "somecommand succeeded"

또는

set -o pipefail
if ! somecommand | filter; then
  echo >&2 "somecommand or filter failed"
  exit 2
fi

Zsh에 대한 옵션은 없지만 pipefail배열에 있는 파이프라인의 각 구성 요소에 대한 상태 코드를 검색할 수 있습니다 pipestatus.

somecommand | filter
if ((pipestatus[1])); then
  echo >&2 "somecommand failed"
  exit 2
fi

다른 쉘에서는 파이프의 상태가 오른쪽 명령의 상태입니다. 왼쪽 명령의 상태를 검색할 수 있는 직접적인 방법은 없습니다. 바라보다종료 상태를 다른 프로세스로 파이프로 가져오기몇 가지 가능한 해결책.

filter의 전체 출력을 읽어야 합니다 . 그렇지 않으면 죽을 때 일어나는 일을 somecommand처리해야 합니다 .somecommand신호 파이프라인.

somecommand종료 상태가 아닌 출력 생성 여부에 따라 조치를 취 하려면 다음을 사용할 수 있습니다.ifne~에서Joey Hess의 moreutils. 대부분의 시스템에는 기본적으로 이러한 유틸리티가 설치되어 있지 않습니다.

답변2

{   ls -lrt /dir1/dir2/filename*.txt || 
    kill $$ 
} | tail -1 | 
awk '{print $9}' | 
read variable

너 자신이 되라 kill. 때때로 쉘은 내가 이 작업을 수행할 때 약간 불평할 수 있지만, 내가 이렇게 하면 쉘은 심지어 불평조차 하지 않는다는 것을 발견했습니다 kill -PIPE $$.

또는 반환 코드와 나머지 사항을 구체적으로 지정하려면 다음을 수행하세요.

trap 'echo some error >&2; exit 1' USR1 $and_or_other_signals
{ ls ... || kill -USR1 $$; } |...

나머지는.. 아마도 다른 방법이겠지..?

touch ~/"a n\$ew file
in 'my home
directory"
v=$(ls -1rdt ~/* || kill -PIPE $$; echo /)
v=${v%?/*}; v=${v##*/}
printf '<%s>' ~/"$v"

산출

</home/mikeserv/a n$ew file
in 'my home
directory>

이렇게 하면 포함된 문자에 관계없이 모든 디렉터리에서 마지막으로 수정된 파일의 이름을 얻을 수 있습니다. < >변수의 시작과 끝을 나타내고 뒤에 공백이 포함되어 있지 않음을 나타내는 데 사용됩니다 . 그리고 이 echo비트는후행 공백이 남아 있습니다.

이는 확실히 파이프를 무력화할 것이며 ls0이 아닌 값이 반환되면(예: 명령줄 인수가 존재하지 않는 경우) 스크립트된 셸을 계속 종료합니다.

정렬 순서를 바꾸지 않고도 동일한 작업을 수행할 수 있지만 약간 까다로우며 이를 쉽게 수행하려면 대상 디렉터리로 변경해야 합니다.

touch ~/"a n\$ew file
in 'my home
directory"
v=$(cd ~; ls -dtm ./* || kill -PIPE $$)
v=${v#*/}; v=${v%%,?./*}
printf '<%s>' ~/"$v"

산출

</home/mikeserv/a n$ew file
in 'my home
directory>

제가 생각하기에 꽤 이식성이 있다고 생각되는 또 다른 접근 방식은 다음과 같습니다.

set /[d]ir1/dir2/filename*.txt
[ -z "${1##/\[*}" ] && exit 1
while [ -n "$2" ] 
do  [ "$1" -nt "$2" ] &&
    set "$@" "$1"
shift; done; v=$1
printf %s\\n "$1" "$v"

관련 정보