grep 명령이 조건문에서 작동하지 않습니다

grep 명령이 조건문에서 작동하지 않습니다

모든 파일 이름을 반복하고 특정 문자(예: "o")가 포함된 파일 이름만 인쇄하는 bash 스크립트가 있습니다.

내가 뭘 한거지:

command=`ls -l`
for file in $command
do
  if $file | grep 'o' ;
  then
  echo "$file"
  fi
done

이것은 작동하지 않습니다. 줄에 "명령을 찾을 수 없습니다"라고 표시됩니다.

if $file | grep 'o' ;

나는 여기에서 몇 가지 다른 답변을 찾았으며 그들은 나와 동일한 작업을 수행하고 있습니다. 즉, 괄호가 없는 if 문, 동일한 구문 등입니다.

내가 무엇을 간과하고 있습니까?

답변1

$file | grep -ofile및 값으로 지정된 명령을 실행합니다.관로grep그러나 이것은 분명히 당신이 원하는 것이 아닙니다 .

다음을 포함하는 파일을 나열하려는 경우o

값은 실행할 명령이 아니라 file입력 파일이라는 뜻입니다. grep그래서 입력이 필요해요리디렉션, 파이프가 아닙니다.

if grep 'o' <"$file"

grep명령줄에 파일 이름이 수신되지 않으면 표준 입력에서 읽습니다. 명령줄에서 파일 이름을 전달할 수도 있습니다. 이는 동일한 작업을 수행합니다.

if grep 'o' -- "$file"

큰따옴표가 사용되는 이유와 --두 번째 접근 방식의 이유는 다음을 참조하세요.공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?

출력을 억제하려면 옵션을 grep사용 -q하거나 출력을 로 리디렉션하세요 /dev/null.

if grep -q 'o' <"$file"

또는

if grep 'o' <"$file" >/dev/null

스크립트의 또 다른 문제는 command=`ls -l`변수를 파일 이름 목록이 아닌 command명령의 출력으로 설정하는 것입니다. ls -l아직도 기억한다면공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?, 저장이 불가능하다는 것을 기억하실 것입니다목록파일 이름변수: 모든 파일 이름이 함께 혼합됩니다. 여기에는 더 나쁜 문제가 있습니다. 권한, 날짜 등의 정크가 있습니다. 쉘 스크립트에서 파일 이름 목록을 얻는 방법은 다음을 사용하는 것입니다.와일드카드 패턴.

for file in *
do
  if grep -q 'o' <"$file"
  then
    echo "$file"
  fi
done

이들 모두는 다음과 같습니다.

grep -l 'o' -- *

이름에 다음이 포함된 파일을 나열하려면o

이 기능은 쉘에 내장되어 있으며와일드카드 패턴. 패턴은 *o*포함된 파일 이름과 일치하므로 o이를 나열하려면 필요합니다.

ls -l -- *o*

--파일 이름 중 하나가 로 시작하는 경우 이는 필수입니다. -그렇지 않으면 ls파일 이름이 옵션으로 해석될 수 있습니다.

이것이 사용법에 대한 학습 연습 grep이고 파일 이름을 입력으로 전달하려는 경우 grep해당 명령을 사용해야 합니다 echo.

echo "$file" | grep 'o'

echo명령은 일부 파일 이름을 손상시킬 수 있습니다. 안전을 유지하려면 를 사용하세요 printf. 이에 대한 자세한 내용과 큰따옴표 사용은 다음을 참조하세요.공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?

printf '%s\n' "$file" | grep 'o'

위에서 언급했듯이 출력은 구문 분석되지 않습니다 ls.

for file in *
do
  if printf '%s\n' "$file" | grep -q 'o'
  then
    printf '%s\n'
  fi
done

파일 이름에 개행 문자가 포함되어 있지 않으면 .

for file in *
do
  printf '%s\n' "$file" | grep 'o'
done

여기서도 루프는 의미가 없습니다.

printf '%s\n' *o*

일치하는 파일 이름을 별도의 줄에 인쇄합니다. grep이는 정규 표현식이 필요하고 쉘의 와일드카드 패턴이 충분하지 않은 경우에만 필요합니다.

답변2

을 실행하려고 합니다 $file. 대신 이를 에코해야 합니다.

# ...
if echo "$file" | grep 'o' ;
# ...

grep은 이미 파일 이름을 인쇄하므로 해당 이름을 음소거해야 합니다(예: grep -q 'o'또는 grep 'o' >/dev/null).

당신은 또한 , 당신 -l에게 전달ls아니요그것을하고 싶다. ls -l일치시킬 파일 이름과 속성을 인쇄하세요.

또한 어떤 파일에서든 작동하도록 하려면 따옴표를 사용해야 할 수도 있지만 이것이 문제의 원인은 아닙니다.

추신: 다른 사람들이 지적했듯이 ls처음에는 사용해서는 안됩니다.

답변3

ls출력에 전혀 의존해서는 안됩니다. ls스크립트에 사용하지 않고 인간 친화적인 출력을 표시하도록 설계되었습니다. 아래 예를 참조하세요.

for f in ./*
  do 
   if [[ $f = *o* ]]; then 
    printf '%s\n' "$f"
   fi
 done

답변4

우선, 이것은 grep에 무언가를 파이프하는 방법이 아닙니다. 또한, 그것은일반적으로 말하면조건에서 명령을 분리하고 반환 코드만 확인하는 더 나은 형태로 간주됩니다.

다음과 같은 것이 완벽하게 작동합니다.

command=`ls -l`
for file in "$command"
do
  echo "$file" | grep 'o'
  if [ $? -eq 0 ]; then
    echo "$file"
  fi
done

관련 정보