781
이름에 포함된 파일 목록의 이름을 저장하려고 합니다. 저는 이 목록으로 뭔가를 할 것이고 그런 다음 이 목록을 삭제할 것입니다.
이를 수행하려면 두 가지 옵션이 있습니다.
옵션 1:다음 명령을 사용하여 목록을 임시 파일에 저장할 수 있습니다.
ls -lart *781* | awk '{print $9}' > tempo
파일에는 tempo
목록이 포함되며 사용 후 파일을 삭제하겠습니다.
옵션 2: 어떻게든 목록을 변수에 저장하고 해당 변수를 사용할 수 있다면. 이를 달성하기 위해 아래 코드를 시도하고 있지만 작동하지 않습니다.
filelist=`ls -lart *781* | awk '{print $9}'`
echo $filelist
그러나 위의 코드는 어떠한 출력도 제공하지 않습니다. 구문 문제를 도와주세요.
편집하다:k-shell을 사용하고 있습니다.
답변1
ls
파일 목록을 얻는 데 사용하지 마십시오 . 특히 ls *
이렇게 하면 빈 디렉토리 행이 많이 제공되므로 더욱 그렇습니다.
다음을 사용할 수 있습니다(항상 좋은 것은 아닙니다).
for file in *781*; do
echo "$file"
done
공백이 있는 파일은 보존되지만 다른 특수 문자가 있는 파일은 보존되지 않습니다.
다음과 같이 할 수도 있습니다.
find . -name "*781*" -print0 | while IFS="" read -r -d "" file; do
echo "$file"
done
어느 것이 더 낫지만 모든 UNIX(Linux도 마찬가지)의 표준은 아닙니다.
모든 경우에 공백을 구분 기호로 사용할 수 없으므로 파일 이름을 단일 변수에 넣지 마십시오. 아마도 다음과 같이 bash 배열을 사용할 수 있습니다.
declare -a file_array
while IFS="" read -r -d "" file; do
file_array[${#file_array[@]}]="$file"
done < <(find . -print0)
프로세스 대체 없이 ksh에서 작업하려면 다음을 수행하세요.
typeset -a file_array
mkfifo mypipe
find . -print0 > mypipe &
while IFS="" read -r -d "" file; do
file_array[${#file_array[@]}]="$file"
done < mypipe
rm mypipe
답변2
익명 파이프의 아이디어와 함수의 출력을 배열의 입력으로 사용해야 하는 필요성에서 영감을 받은 제안을 통해 코프로세스가 도움이 될 수 있다는 것을 알았습니다.
MyFunction()
{ echo "One line" ; echo "Second line" ; echo "Third line" }
set -A array
MyFunction 'SomeInputToFunction' < /dev/null |&
while read -p -r line; do
print "READING from co-process: $line"
array[ ${#array[@]} ]="$line"
done
산출:
READING from MyFunction co-process: One line
READING from MyFunction co-process: Second line
READING from MyFunction co-process: Third line
이전 포스터에 많은 감사를 드립니다! ——페르난도 곤잘레스
답변3
어떤 쉘을 사용하고 있는지 확실하지 않지만 bash
export filelist=`ls -lart *781* | awk '{print $9}'`
echo $filelist
예를 들어:
export filelist=`ls -l|awk '{print $4}'`
echo $filelist
root root sys nobody sys sys sys sys root sys bin root sys root other sys sys root root sys other root sys root sys sys root root
답변4
왜 귀하의 예가 작동하지 않는지 모르겠습니다. 여기에서 작동합니다. 모든 파일과 일치하는 전역 표현식을 사용하는 경우입니다. 일치하는 항목이 디렉터리일 수 있고 해당 디렉터리의 내용이 나열되는 -d
것을 원하지 않는 경우 ls
.
glob 표현식이 어떤 파일과도 일치하지 않을 때 어떤 일이 발생하는지 주의해야 합니다. Bash에는 활성화할 수 있는 설정이 있으며 shopt -s failglob
, 이 경우 오류가 발생합니다. 다른 쉘에서 또는 bash에서 이 옵션이 활성화되지 않은 경우 glob 표현식 자체가 출력으로 표시됩니다. 그냥 수행하면 echo nonmatching_expression*
"nonmatching_expression*"이라는 결과가 표시됩니다. 이렇게 하면 ls nonmatching_expression*
ls에서 오류가 발생합니다.
작성된 대로 두 옵션 모두 파일 이름에 공백이 포함되어 있지 않다고 가정합니다. ls -l ... | awk '{print $9}'
파일 이름에 공백이 포함되어 있지 않다면 괜찮습니다 . (그런데 왜 ls -l ... | awk '{print $9}'
그냥 사용하지 않고 을 사용하고 있는 걸까요 ls
? 위의 예시에 반영되지 않은 이유가 있을 것으로 추측됩니다.)
파일 이름에 개행 문자가 포함되어 있으면 상황은 훨씬 더 어려워집니다. 이 경우 어떻게 해야 하는지는 다루지 않겠습니다. 개행 문자는 포함하지 않지만 다른 공백을 포함할 수 있는 경우 -l
on 플래그를 생략 ls
하고 awk에 대한 파이프를 생략할 수 있습니다. 그런 다음 첫 번째 옵션은 한 줄에 하나의 파일 이름을 임시 파일에 저장합니다. 이러한 파일 이름에는 공백이나 탭이 포함될 수 있습니다(단, 줄바꿈은 포함되지 않음). 두 번째 옵션도 한 줄에 하나의 파일 이름을 변수에 저장하지만 사용하기가 더 어렵습니다.
파일 이름 목록을 변수에 저장했고 파일 이름에 공백이 포함될 수 있는 경우 변수를 확장할 때 항상 변수를 인용해야 합니다. 따라서 echo "$filelist"
not 을 사용하십시오 echo $filelist
.
데이터를 추출하는 방법은 다음과 같습니다.
옵션 1:
while IFS= read -r f; do
do_stuff_with "$f"
done < tempo
옵션 2:
while IFS= read -r f; do
do_stuff_with "$f"
done << EOF
$filelist
EOF
이러한 메서드를 사용하면 스크립트의 나머지 부분에 표시되는 루프 내에서 작업(변수 수정, 디렉터리 변경)을 수행할 수 있습니다. 이에 대해 신경 쓰지 않는다면 while ... done
다음과 같이 해당 부분을 파이프라인에 넣을 수 있습니다.
echo "$filelist" | while IFS= read -r f; do
do_stuff_with "$f"
done
이 경우 전체 while ... done
구성은 서브셸에서 실행되며 변수( 루프 포함 f
)에 대한 모든 수정 사항은 해당 서브셸 내에서만 표시됩니다.
Bash 및 기타 일부 쉘에는 배열 변수가 있습니다. 어떤 사람들은 파일 이름에 공백이 포함될 때 사용하기가 더 쉽다고 생각합니다. 그러나 휴대성이 떨어집니다. 그리고 내보낼 수 없습니다. (질문에 태그를 붙인 것은 /environment-variables
변수가 내보내진다는 의미입니다. 하지만 그런 뜻은 아닐 수도 있습니다.) 여기서는 목적에 맞게 배열 변수를 사용하는 방법에 대해 논의하지 않겠습니다.
파일 이름에 공백이 없다는 것을 알고 있는 경우 가장 쉬운 방법은 옵션 2를 사용하는 것이며 다음을 사용할 수 있습니다.
for f in $filenames; do
do_stuff_with $f
done
여기서는 따옴표를 생략해야 하며 $filenames
, around는 선택 사항입니다 $f
.