ls
디렉토리 이름 목록을 위해 무언가를 수행하고 각각을 반복 하고 무언가를 수행하기위한 템플릿 쉘 스크립트가 있습니까?
나는 할 계획입니다 ls -1d */
디렉토리 이름의 목록을 얻을 수 있습니다.
ls
디렉토리 이름 목록을 위해 무언가를 수행하고 각각을 반복 하고 무언가를 수행하기위한 템플릿 쉘 스크립트가 있습니까?
나는 할 계획입니다 ls -1d */
디렉토리 이름의 목록을 얻을 수 있습니다.
답변:
@ shawn-j-goff와 다른 사람들이 제안했듯이 글로브가 할 위치에 ls를 사용하지 않도록 편집했습니다.
for..do..done
루프를 사용하십시오 .
for f in *; do
echo "File -> $f"
done
당신은 대체 할 수 *
와 *.txt
나 (그 문제에 대해 파일, 디렉토리, 또는 아무것도의) 목록을 반환하는 모든 다른 글로브, 목록을 생성하는 명령, 예를 들어,이, $(cat filelist.txt)
또는 실제로 목록으로 대체합니다.
do
루프 내에서 달러 기호 접두사가 붙은 루프 변수를 참조하면됩니다 ( $f
위의 예에서와 같이). 당신이 할 echo
수 있거나 원하는 다른 일을 할 수 있습니다.
예를 들어, 모든 이름을 바꾸려면 .xml
현재 디렉토리에있는 파일을 .txt
:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
또는 Bash를 사용하는 경우 하위 쉘을 생성하는 대신 Bash 매개 변수 확장을 사용할 수 있습니다.
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
for
루프의 일반적인 오용 과의 출력을 파싱하려는 전형적인 함정을 보여줍니다 ls
. @ DanielA.White, 당신 이 말한 것처럼 디렉토리에서 작업하고 있기 때문에 도움이되지 않거나 잠재적으로 오도 된 경우이 답변을 수락 하지 않는 것을 고려할 수 있습니다 . Shawn J. Goff의 답변은 문제에 대한보다 강력하고 효과적인 해결책을 제공해야합니다.
ls
출력을 , 당신은 출력 읽을해야 for
루프를 , 당신은 사용해야합니다 $()
``대신하고 더 많은 따옴표를 사용하여 ™ . @CoverosGene이 잘 의미한다고 확신하지만 이것은 끔찍합니다.
ls
은 ls -1 | while read line; do stuff; done
입니다. 최소한 그 공백은 깨지지 않습니다.
mv -v
당신이 필요하지 않습니다echo "moved $x -> $t"
출력을 사용하여 ls
파일 이름을 얻는 것은 나쁜 생각 입니다. 오작동이나 위험한 스크립트로 이어질 수 있습니다. 파일 이름을 제외한 모든 문자를 포함 할 수 있기 때문이다 /
과 null
문자 및 ls
구분 기호로 이러한 문자 중 하나를 사용하지 않기 때문에 파일 이름에 공백이나 줄 바꿈이있는 경우, 당신은 것 예상치 못한 결과를 얻을 수 있습니다.
파일을 반복하는 두 가지 좋은 방법이 있습니다. 여기서는 단순히 echo
파일 이름으로 무언가를 수행하는 것을 보여주기 위해 사용했습니다 . 그래도 무엇이든 사용할 수 있습니다.
첫 번째는 쉘의 기본 글 로빙 기능을 사용하는 것입니다.
for dir in */; do
echo "$dir"
done
쉘 */
은 for
루프가 읽는 별도의 인수로 확장 됩니다 . 파일 이름에 공백, 줄 바꿈 또는 기타 이상한 문자가 있더라도 for
각 완전한 이름을 원자 단위로 볼 수 있습니다. 어떤 식 으로든 목록을 구문 분석하지 않습니다.
당신이 하위 디렉토리로 재귀 적으로 가고 싶은 경우 쉘과 같은 몇 가지 확장 로빙 기능 (하지 않는 한, 이것은하지 않을 것이다 bash
s '을 (를) globstar
쉘이 이러한 기능이없는 경우. 또는 당신이 확인하고 싶은 경우 스크립트가 작동합니다 다양한 시스템에서 다음 옵션은을 사용하는 것 find
입니다.
find . -type d -exec echo '{}' \;
여기서 find
명령은 echo
파일 이름의 인수를 호출 하여 전달합니다. 찾은 각 파일에 대해이 작업을 한 번 수행합니다. 이전 예제와 마찬가지로 파일 이름 목록을 구문 분석하지 않습니다. 대신 파일 이름이 인수로 완전히 전송됩니다.
-exec
논쟁 의 구문은 약간 재미있어 보인다. find
이후에 첫 번째 인수 -exec
를 사용하여 해당 프로그램을 실행할 프로그램으로 처리하고 이후의 모든 인수는 해당 프로그램에 전달하는 인수로 사용합니다. 확인 -exec
해야 할 두 가지 특별한 주장이 있습니다. 첫 번째는 {}
; 이 인수는 이전 부분이 find
생성 하는 파일 이름으로 대체 됩니다. 두 번째는이며 ;
, 이것이 find
프로그램에 전달할 인수 목록의 끝임을 알려줍니다. 실행 된 프로그램을위한 것이 아닌 find
더 많은 인수를 계속할 수 있기 때문에 이것이 필요합니다 find
. 그 이유 \
는 껍질도 취급하기 때문입니다;
특히-명령의 끝을 나타내므로 쉘이 명령 find
자체를 소비하는 대신 인수로 제공하도록 명령을 이스케이프 처리해야 합니다. 쉘을 특별하게 취급하지 않도록하는 또 다른 방법은 따옴표로 묶는 것입니다.이 목적 ';'
뿐만 아니라 작동합니다 \;
.
find
. 할 수있는 마술이 있으며, 인식 된 한계조차도 -exec
해결할 수 있습니다. 이 -print0
옵션은와 함께 사용할 수도 있습니다 xargs
.
공백이있는 파일의 경우 다음과 같이 변수를 인용해야합니다.
for i in $(ls); do echo "$i"; done;
또는 입력 필드 구분 기호 (IFS) 환경 변수를 변경할 수 있습니다.
IFS=$'\n';for file in $(ls); do echo $i; done
마지막으로 수행중인 작업에 따라 ls가 필요하지 않을 수도 있습니다.
for i in *; do echo "$i"; done;
\n
이 충분하지 않습니다. 의 출력 구문 분석을 권장하지 않는 것이 좋습니다 ls
.
GNU Parallel http://www.gnu.org/software/parallel/을 설치 한 경우 다음을 수행 할 수 있습니다.
ls | parallel echo {} is in this dir
모든 .txt의 이름을 .xml로 바꾸려면
ls *.txt | parallel mv {} {.}.xml
자세한 내용은 GNU Parallel 소개 비디오를 참조하십시오 . http://www.youtube.com/watch?v=OpaiGYxkSuQ
왜 IFS를 줄 바꿈으로 설정 ls
하고 배열 의 출력을 캡처하지 않습니까? IFS를 줄 바꿈으로 설정하면 파일 이름에 재미있는 문자가있는 문제가 해결됩니다. ls
내장 정렬 기능이 있기 때문에 사용하는 것이 좋습니다.
(테스트에서 IFS를 \n
설정하는 데 문제가 있었지만 다른 곳에서 제안한 것처럼 줄 바꿈 백 스페이스로 설정하면 작동합니다).
예 : (원하는 ls
검색 패턴이 전달 되었다고 가정 $1
) :
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
FILES=($(/bin/ls "$1"))
for AFILE in ${FILES[@]}
do
... do something with a file ...
done
IFS=$SAVEIFS
예를 들어, 생성 날짜 (가장 오래된 것부터 가장 오래된 것까지)로 정렬 된 파일 목록을 캡처하기 위해 OS X에서 특히 유용합니다 . ls
명령은 ls -t -U -r
입니다.
\n
이 충분하지 않습니다. 유일하게 유효한 솔루션은 경로 이름이 확장 된 for 루프 또는를 사용합니다 find
.
이것이 내가하는 방법이지만 더 효율적인 방법이있을 수 있습니다.
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done