나는 다음 줄을 포함하는 이 스크립트를 작성 중입니다.
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
비트는예후행 공백이 남아 있습니다.
이는 확실히 파이프를 무력화할 것이며 ls
0이 아닌 값이 반환되면(예: 명령줄 인수가 존재하지 않는 경우) 스크립트된 셸을 계속 종료합니다.
정렬 순서를 바꾸지 않고도 동일한 작업을 수행할 수 있지만 약간 까다로우며 이를 쉽게 수행하려면 대상 디렉터리로 변경해야 합니다.
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"