명령 출력에 성공하면 파이프 출력


14
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`

head -1첫 번째 명령이 성공한 경우에만 두 번째 명령 ( ) 을 실행하고 싶었 습니다. 이 명령을 어떻게 개선합니까?


성공한다는 것은 무엇을 의미합니까? ls실패하지 않습니다.
Matteo

2
그러나 일치하는 파일이 없으면 glob이 실패 할 수 있습니다.
tripleee

답변:


8

이 시도:

INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml | head -1 | xargs -r basename`

플래그를 전달 xargs하면 표준 입력 ( ) 에서 하나 이상의 항목을 읽는 경우 -r에만 실행 basename됩니다 head -1.

head -1 실행되지만 출력을 보거나 캡처하지 않습니다.

또한 사용자에게의 오류 출력이 표시되지 않게하려면 의 stderr 스트림을로 ls리디렉션 할 수 있습니다 .ls/dev/null

INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename`

또한 주위에 따옴표를 추가했습니다 $MY_DIR. 이렇게하면 $MY_DIR공백이 있으면 명령이 실패하지 않습니다 .

bash와 같은 최신 쉘을 사용하는 경우 $( )백틱 대신 캡처 쉘을 사용해야합니다 . 변수 스타일 변경도 고려해야합니다. 일반적으로 스크립트에서 모든 대문자 변수 이름을 사용하지 않아야합니다. 이 스타일은 일반적으로 예약 및 환경 변수를 위해 예약되어 있습니다.

input_file=$(ls -rt "$my_dir"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename)

파일이없는 경우이 b0rk이 아닙니까?
Mel Boyce

실제로 : ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basename작동합니다.
Mel Boyce

@ MelBoyce : 나는 그것을 내 대답에 추가했습니다. 감사.

ls는 대화식으로 파일 정보를 보는 도구입니다. 출력은 사람을 위해 형식화되며 스크립트에서 버그가 발생합니다. 글로브를 사용하거나 대신 찾으십시오. 이유를 이해하십시오 : mywiki.wooledge.org/ParsingLs
cinelli

@cinelli : 사실입니다. 나는 그 질문에 대답하고 있었다.

9

파이프 라인에서 모든 명령은 차례대로 시작되고 동시에 실행되지 않습니다. 따라서 출력을 어딘가에 저장해야합니다.

if ls_output=$(ls -rtd -- "$MY_DIR"/FILE.*.xml); then
  first_file=$(printf '%s\n' "$ls_output" | head -n 1)
  first_file_name=$(basename -- "$first_file")
fi

파일 이름에 줄 바꿈 문자가 포함되어 있지 않다고 가정합니다. xargs빈 문자, 작은 따옴표 및 큰 따옴표 및 백 슬래시와 관련된 문제도 사용 됩니다. 인용 부호가없는 변수는 공백, 탭 및 와일드 카드 문자에 문제가 있음을 의미합니다. 잊어 버리면로 --시작하는 파일 이름에 문제가있는 것입니다 -.

zsh문자에 대한 제한없이 가장 오래된 파일의 기본 이름을 얻으려면 (명령에 대한 제한된 크기의 인수 문제도 피하십시오) :

 first_file_name=($MY_DIR/FILE.*.xml(Om[1]:t))

일치하지 않으면 해당 명령이 실패하고 스크립트가 중단됩니다. 당신은 또한 할 수 있습니다 :

 first_file_name=($MY_DIR/FILE.*.xml(NOm[1]:t))

이 경우 first_file_name일치하는 항목이 있으면 배열에 1 개의 요소가 포함되고 그렇지 않으면 0이 포함됩니다. 그런 다음 다음을 수행 할 수 있습니다.

 if (($#first_file_name)); then
    printf 'Match: %s\n' $first_file_name
 else
    echo >&2 No match
 fi

4

디렉토리에서 최신 수정 된 파일을 찾으십시오.

latest() {
  local file path=${1:-.} ext=${2-} latest
  for file in "${path%/}"/*"$ext"; do 
    [[ $file -nt $latest ]] && latest=$file
  done
  [[ $latest ]] && printf '%s\n' "$latest"
}

용법: latest [directory/path/ [.extension]]

를 호출하는 대신 basename매개 변수 확장을 사용하십시오.

in_file=$(latest in/my/dir .xml)
base_fn=${in_file##*/} base_fn=${base_fn%.*}

다음 내용이 포함 된 디렉토리에서 :

foo.xml bar.xml baz.xml newest.xml

base_fn 변수의 내용은 다음과 같습니다. newest

요청 목적을 위해 이것을 올바르게 사용하려면 다음을 수행하십시오.

check_dir=/path/to/check
check_ext=.xml
if in_file=$(latest "$check_dir" "$check_ext"); then
  base_fn=${in_file##*/} base_fn=${base_fn%.*}
else
  printf '%s\n' "No file found in $check_dir" >&2
fi

편집 : 질문을 검토 한 결과, 해당 ls명령 이 디렉토리에서 가장 오래된 파일을 찾고 있음을 깨달았습니다 . 이 같은 함수로 변경 될 수있다 oldest하고있는 [[ $file -ot $oldest ]] && oldest=$file동일한 효과를 달성하는 대신. 혼란에 대한 사과드립니다.

주목해야 할 것은 인류의 어떤 상황에서도 절대적으로 ls의 결과를 파싱해서는 안된다는 것입니다. 못.


ls기반 접근 방식 과 달리 심볼릭 링크가있는 경우 심볼릭 링크 대상의 수정 시간이 고려됩니다 ( 동일한 동작을 얻을 수있는 -L옵션 추가 ls).
Stéphane Chazelas 2016 년

0

가장 좋은 옵션은 다음과 같습니다.

ls -rf $MY_DIR/FILE.*.xml
if [ $? -eq 0 ]; then
      INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml|head -1|xargs basename `
else
      echo "Error!"
fi

파일이 없으면 ls의 리턴 코드는 2이지만 일부 파일이 발견되면 0이됩니다.


2
대신에 비교하는 $?대한을 0, 당신은이 작업을 수행 할 수 있습니다 if ls -rf $MY_DIR/FILE.*.xml ; then.

또한 첫 번째 comand의 출력을로 리디렉션 할 수 있습니다 /dev/null. ls -rf $MY_DIR/FILE.*.xml &> /dev/null. 이렇게하면 사용자에게 추가 출력이 표시되지 않습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.