오류: 출력을 명령으로 파이프할 때 모호한 리디렉션

오류: 출력을 명령으로 파이프할 때 모호한 리디렉션

스크립트에서 출력이 리디렉션되었습니다.

$ ls -ltr |awk '{print $9}'

default.txt
dfah.txt
fruit.txt
fruit_prices.txt
dfh.txt
header.txt
testfile.txt
topoutput.txt

쉘에 작성된 스크립트:

while read line
do 
var=`sed -e 's/\.txt/txt\.txt/' $line`
 echo $var
 done < `ls -ltr |awk '{print $9}'`

에러 발생됨:

-bash: `ls -ltr |awk '{print $9}'`: ambiguous redirect

위 코드에서 모호한 리디렉션이 어떻게 발생하는지 전문가의 도움을 받을 수 있습니까?

답변1

노력하다

ls -ltr |awk '{print $9}' | while read line
do 
  var=`sed -e 's/\.txt/txt\.txt/' $line`
  echo $var
done 

이 명령을 내렸습니다.

while read line ; do
  ...
 done < a b c d

구문 분석할 수 없음

답변2

하려고 하는 것 같군요

while read line
do
  ...
done < <(ls -ltr | awk '{print $9}')

그런데 왜? (while read line아케마의 대답)가 더 명확하고 이식성이 뛰어납니다.

좋습니다. 답변을 더욱 완전하게 만들려면 다음을 수행하세요.졸탄 뵈스조르메니(Zoltán Böszörményi)는 다음과 같이 지적합니다.,

ls -ltr | awk '{print $9}' | while read line
do
  ...
done

Bash(및 기타 일부 셸)에서는 주체가 subshell 에서 실행되므로 while셸 상태(예: 셸 변수)에 대한 상태 변경이 루프 외부에서 지속되지 않습니다. 이에 대해서는 다음 장소에서 더 자세히 논의됩니다.

< <(…)이 답변 상단의 코드는 문제를 피하는 한 가지 방법입니다.


하지만 또 다른 것

당신은하고 있습니다 ls -ltr | awk '{print $9}'. 이는 수정된 날짜/시간 순으로 파일을 나열한 다음 파일 이름을 추출하는 패치워크처럼 보입니다. 몇 가지 질문이 있습니다:

  • 공백이 포함된 파일 이름의 경우 이 작업이 실패합니다.
  • ls생성하라고 하면 스스로 추가 작업을 수행하는 것입니다.정보(파일 모드, 소유자, 크기 등)를 나열한 다음 처음에 생성할 필요가 없으면 제거합니다.

생략하면 두 가지 문제를 모두 해결할 수 있습니다.l옵션  ls및 생략  awk:

while read line
do
  ...
done < <(ls -tr)

공백으로 시작하거나 끝나는 파일 이름은 여전히 ​​문제를 일으킬 수 있습니다.

당신은 또한 볼 수 있습니다ls(1)의 출력을 분석하면 안되는 이유.

답변3

"cat file | while read line ..."은 서브쉘에서 "while"의 본문을 실행하기 때문에 쉘 변수는 서브쉘 외부에 표시되지 않지만 "while read line ; do ... ; did < <(command )"를 사용하여 동일한 쉘에서 실행합니다.

이것은 내 테스트 파일입니다.

$ cat fruits.txt
apple
cherry
pear
plum

두 스크립트와 결과의 차이점을 살펴보세요.

$ cat a.sh
#!/bin/bash

FOUND=0

while read fruit ; do
    case $fruit in
    cherry)
        echo yay, cherry found
        FOUND=1
        ;;
    esac
done < <(cat fruits.txt)
echo cherry found: $FOUND

$ ./a.sh
yay, cherry found
cherry found: 1

하지만

$ cat b.sh 
#!/bin/bash

FOUND=0

cat fruits.txt | while read fruit ; do
    case $fruit in
    cherry)
        echo yay, cherry found
        FOUND=1
        ;;
    esac
done
echo cherry found: $FOUND
$ ./b.sh 
yay, cherry found
cherry found: 0

답변4

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

while read line; do
    var=`echo "$line" |sed -e 's/\.txt/txt\.txt/'`
    echo $var
done <<_EOT_
$(ls -ltr | awk '{print $9}')
_EOT_

관련 정보