배시 루프 목록에서 공백을 이스케이프하려면 어떻게 해야 합니까?
특정 디렉터리의 모든 하위 디렉터리(파일 제외)를 순환하는 bash 셸 스크립트가 있습니다.문제는 일부 디렉토리 이름에 공백이 포함되어 있다는 것입니다.
테스트 디렉토리의 내용은 다음과 같습니다.
$ls -F test
Baltimore/ Cherry Hill/ Edison/ New York City/ Philadelphia/ cities.txt
그리고 디렉터리를 순환하는 코드:
for f in `find test/* -type d`; do
echo $f
done
다음은 출력입니다.
테스트/볼티모어테스트/체리힐테스트/에디슨테스트/신규요크도시필라델피아 시험
Cherry Hill과 New York City는 2개 또는 3개의 개별 항목으로 처리됩니다.
다음과 같이 파일 이름을 인용해 보았습니다.
for f in `find test/* -type d | sed -e 's/^/\"/' | sed -e 's/$/\"/'`; do
echo $f
done
하지만 소용이 없습니다.
이것을 할 수 있는 간단한 방법이 있을 것입니다.
아래의 답변은 훌륭합니다.그러나 이 문제를 더욱 복잡하게 만들기 위해 테스트 디렉토리에 나열된 디렉토리를 항상 사용하지는 않습니다.디렉토리 이름을 대신 명령줄 매개 변수로 전달하고 싶을 때가 있습니다.
IFS를 설정하자는 찰스의 제안을 받아들여 다음과 같은 것을 생각해 냈습니다.
dirlist="${@}"
(
[[ -z "$dirlist" ]] && dirlist=`find test -mindepth 1 -type d` && IFS=$'\n'
for d in $dirlist; do
echo $d
done
)
명령줄 인수에 공백이 없는 경우(인수가 따옴표로 묶인 경우에도) 이 작업이 제대로 수행됩니다.를 들어,를 이렇게 것입니다: 예를들스트다같음호이출다니합과를크어.test.sh "Cherry Hill" "New York City"
과 같은출력을 합니다.
체리힐신규요크도시
첫째, 그런 식으로 하지 마세요.가장 좋은 접근 방식은 다음을 사용하는 것입니다.find -exec
적절하게:
# this is safe
find test -type d -exec echo '{}' +
은 NUL이지만, 을 찾을 수 . NUL 종료 목록을 사용해야 합니다.-print0
:
# this is safe
while IFS= read -r -d '' n; do
printf '%q\n' "$n"
done < <(find test -mindepth 1 -type d -print0)
찾기에서 배열을 채우고 나중에 해당 배열을 전달할 수도 있습니다.
# this is safe
declare -a myarray
while IFS= read -r -d '' n; do
myarray+=( "$n" )
done < <(find test -mindepth 1 -type d -print0)
printf '%q\n' "${myarray[@]}" # printf is an example; use it however you want
검색결지지않는경우되를 지원하지 ,-print0
그러면 결과가 안전하지 않습니다. 이름에 새 줄이 포함된 파일이 있는 경우(예, 합법적인 파일인 경우) 다음과 같이 원하는 대로 작동하지 않습니다.
# this is unsafe
while IFS= read -r n; do
printf '%q\n' "$n"
done < <(find test -mindepth 1 -type d)
방법 중 세 사용은 단어 전에 때문에 입니다.IFS
공백 문자를 포함하지 않는 변수입니다.글로빙해제(해제▁turn▁glob글▁offbingset -f
)와[]
,*
또는?
확장으로부터:
# this is unsafe (but less unsafe than it would be without the following precautions)
(
IFS=$'\n' # split only on newlines
set -f # disable globbing
for n in $(find test -mindepth 1 -type d); do
printf '%q\n' "$n"
done
)
마지막으로 명령줄 매개 변수의 경우 셸에서 지원하는 어레이(즉, ksh, bash 또는 zsh)를 사용해야 합니다.
# this is safe
for d in "$@"; do
printf '%s\n' "$d"
done
분리를 유지할 것입니다.인용문(및 의 사용)에 유의하십시오.$@
$*
이 중요합니다이 중요합니다.배열은 글로벌 식과 같은 다른 방법으로도 채울 수 있습니다.
# this is safe
entries=( test/* )
for d in "${entries[@]}"; do
printf '%s\n' "$d"
done
find . -type d | while read file; do echo $file; done
그러나 파일 이름에 새 줄이 포함된 경우에는 작동하지 않습니다.위의 방법은 실제로 디렉터리 이름을 변수에 넣고 싶을 때 사용할 수 있는 유일한 방법입니다.일부 명령만 실행하려면 xargs를 사용합니다.
find . -type d -print0 | xargs -0 echo 'The directory is: '
다음은 파일 이름의 탭 및/또는 공백을 처리하는 간단한 솔루션입니다.파일 이름의 다른 이상한 문자를 새 줄처럼 처리해야 하는 경우 다른 답을 선택합니다.
테스트 디렉토리
ls -F test
Baltimore/ Cherry Hill/ Edison/ New York City/ Philadelphia/ cities.txt
디렉토리에 들어갈 코드
find test -type d | while read f ; do
echo "$f"
done
로 묶어야 ."$f"
을을 인수로 사용할 경우.따옴표를 사용하지 않으면 공백이 인수 구분 기호로 작동하고 호출된 명령에 여러 인수가 지정됩니다.
그리고 출력:
test/Baltimore
test/Cherry Hill
test/Edison
test/New York City
test/Philadelphia
이것은 표준 유닉스에서는 매우 까다롭고 대부분의 솔루션은 줄 바꿈이나 다른 문자로 실행됩니다.에는 GNU 툴 를 이용할 수 .find
택-print0
및사를 합니다.xargs
하는 옵션이 있는 -0
(영문-영문).단순 파일 이름에는 슬래시와 NUL '\0'이라는 두 문자가 표시되지 않습니다.분명히 슬래시는 경로 이름으로 나타나므로 이름의 끝을 표시하기 위해 NUL '\0'을 사용하는 GNU 솔루션은 기발하고 바보가 되지 않습니다.
다음을 사용하여 IFS(내부 필드 구분 기호)를 일시적으로 사용할 수 있습니다.
OLD_IFS=$IFS # Stores Default IFS
IFS=$'\n' # Set it to line break
for f in `find test/* -type d`; do
echo $f
done
IFS=$OLD_IFS
<!>
그냥 놔두는 게 어때요?
IFS='\n'
명령어 앞에서?필드 구분 기호가 <스페이스><탭><새줄>에서 <새줄>로만 변경됩니다.
find . -print0|while read -d $'\0' file; do echo "$file"; done
사용합니다
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for f in $( find "$1" -type d ! -path "$1" )
do
echo $f
done
IFS=$SAVEIFS
그걸로 충분하지 않을까요?
http://www.cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html 에서 가져온 아이디어
목록을 문자열로 저장하지 않고 배열로 저장하여 이러한 구분 기호의 혼동을 방지합니다.다음은 테스트의 모든 하위 디렉터리에서 작동하거나 명령줄에 제공된 목록에서 작동하는 스크립트의 예입니다.
#!/bin/bash
if [ $# -eq 0 ]; then
# if no args supplies, build a list of subdirs of test/
dirlist=() # start with empty list
for f in test/*; do # for each item in test/ ...
if [ -d "$f" ]; then # if it's a subdir...
dirlist=("${dirlist[@]}" "$f") # add it to the list
fi
done
else
# if args were supplied, copy the list of args into dirlist
dirlist=("$@")
fi
# now loop through dirlist, operating on each one
for dir in "${dirlist[@]}"; do
printf "Directory: %s\n" "$dir"
done
이제 한두 개의 곡선이 삽입된 테스트 디렉토리에서 이를 시도해 보겠습니다.
$ ls -F test
Baltimore/
Cherry Hill/
Edison/
New York City/
Philadelphia/
this is a dirname with quotes, lfs, escapes: "\''?'?\e\n\d/
this is a file, not a directory
$ ./test.sh
Directory: test/Baltimore
Directory: test/Cherry Hill
Directory: test/Edison
Directory: test/New York City
Directory: test/Philadelphia
Directory: test/this is a dirname with quotes, lfs, escapes: "\''
'
\e\n\d
$ ./test.sh "Cherry Hill" "New York City"
Directory: Cherry Hill
Directory: New York City
ps 만약 그것이 단지 입력의 공간에 관한 것이라면, 몇몇 이중 따옴표들은 나에게 부드럽게 작동했습니다...
read artist;
find "/mnt/2tb_USB_hard_disc/p_music/$artist" -type f -name *.mp3 -exec mpg123 '{}' \;
Jonathan이 말한 것에 추가하기: 사용-print0
을 선택할 수 .find
xargs
다음과 같이:
find test/* -type d -print0 | xargs -0 command
그면명령실니다됩행이 이 실행됩니다.command
적절한 인수를 사용하면 공백이 있는 디렉터리가 적절하게 따옴표로 묶입니다(즉, 하나의 인수로 전달됨).
#!/bin/bash
dirtys=()
for folder in *
do
if [ -d "$folder" ]; then
dirtys=("${dirtys[@]}" "$folder")
fi
done
for dir in "${dirtys[@]}"
do
for file in "$dir"/\*.mov # <== *.mov
do
#dir_e=`echo "$dir" | sed 's/[[:space:]]/\\\ /g'` -- This line will replace each space into '\ '
out=`echo "$file" | sed 's/\(.*\)\/\(.*\)/\2/'` # These two line code can be written in one line using multiple sed commands.
out=`echo "$out" | sed 's/[[:space:]]/_/g'`
#echo "ffmpeg -i $out_e -sameq -vcodec msmpeg4v2 -acodec pcm_u8 $dir_e/${out/%mov/avi}"
`ffmpeg -i "$file" -sameq -vcodec msmpeg4v2 -acodec pcm_u8 "$dir"/${out/%mov/avi}`
done
done
위의 코드는 .mov 파일을 .avi로 변환합니다..mov 파일은 다른 폴더에 있으며 폴더 이름에도 공백이 있습니다.위 스크립트는 .mov 파일을 같은 폴더에 있는 .avi 파일로 변환합니다.그게 당신들에게 도움이 되는지 모르겠습니다.
사례:
[sony@localhost shell_tutorial]$ ls
Chapter 01 - Introduction Chapter 02 - Your First Shell Script
[sony@localhost shell_tutorial]$ cd Chapter\ 01\ -\ Introduction/
[sony@localhost Chapter 01 - Introduction]$ ls
0101 - About this Course.mov 0102 - Course Structure.mov
[sony@localhost Chapter 01 - Introduction]$ ./above_script
... successfully executed.
[sony@localhost Chapter 01 - Introduction]$ ls
0101_-_About_this_Course.avi 0102_-_Course_Structure.avi
0101 - About this Course.mov 0102 - Course Structure.mov
[sony@localhost Chapter 01 - Introduction]$ CHEERS!
건배!
경로 이름의 공백도 처리해야 했습니다.으로 한 와 결국제한재이것귀고이었용한를은일가▁a,for item in /path/*
:
function recursedir {
local item
for item in "${1%/}"/*
do
if [ -d "$item" ]
then
recursedir "$item"
else
command
fi
done
}
파일 목록을 Bash 배열로 변환합니다.이는 Matt McClure의 접근 방식을 사용하여 Bash 함수에서 배열을 반환합니다. http://notes-matthewlmcclure.blogspot.com/2009/12/return-array-from-bash-function-v-2.html 결과는 다중 줄 입력을 Bash 배열로 변환하는 방법입니다.
#!/bin/bash
# This is the command where we want to convert the output to an array.
# Output is: fileSize fileNameIncludingPath
multiLineCommand="find . -mindepth 1 -printf '%s %p\\n'"
# This eval converts the multi-line output of multiLineCommand to a
# Bash array. To convert stdin, remove: < <(eval "$multiLineCommand" )
eval "declare -a myArray=`( arr=(); while read -r line; do arr[${#arr[@]}]="$line"; done; declare -p arr | sed -e 's/^declare -a arr=//' ) < <(eval "$multiLineCommand" )`"
for f in "${myArray[@]}"
do
echo "Element: $f"
done
이 접근 방식은 잘못된 문자가 있는 경우에도 작동하는 것으로 보이며 모든 입력을 Bash 배열로 변환하는 일반적인 방법입니다.단점은 입력이 길면 Bash의 명령줄 크기 제한을 초과하거나 메모리를 대량으로 사용할 수 있다는 것입니다.
목록에서 최종적으로 작동하는 루프가 있는 접근 방식은 (사용자에게 입력을 요청하는 등) stdin을 읽는 것이 쉽지 않다는 단점이 있으며 루프는 새로운 프로세스이므로 루프가 완료된 후 루프 내부에서 설정한 변수를 사용할 수 없는 이유가 궁금할 수 있습니다.
저는 또한 IFS를 설정하는 것을 싫어합니다. 다른 코드를 망칠 수 있습니다.
저는 너무 많은 복잡한 답들을 봅니다.find 유틸리티의 출력을 전달하거나 루프를 작성하고 싶지 않습니다. find에는 이에 대한 "exec" 옵션이 있기 때문입니다.
제 문제는 dbf 확장자가 있는 모든 파일을 현재 폴더로 이동하고 싶었고 일부 파일에는 공백이 포함되어 있었습니다.
나는 그렇게 태클을 걸었습니다.
find . -name \*.dbf -print0 -exec mv '{}' . ';'
나한테는 훨씬 간단해 보입니다.
방금 제 질문과 당신의 질문 사이에 몇 가지 유사점이 있다는 것을 알게 되었습니다.명령에 인수를 전달하려는 경우에도 마찬가지입니다.
test.sh "Cherry Hill" "New York City"
그것들을 순서대로 인쇄하기 위해
for SOME_ARG in "$@"
do
echo "$SOME_ARG";
done;
$@는 큰따옴표로 둘러싸여 있습니다. 여기에 메모가 있습니다.
특정 폴더에서 여러 디렉터리 또는 파일을 순차적으로 압축하려면 동일한 개념이 필요했습니다.저는 ls에서 리스트를 파싱하고 이름에 공백이 생기는 문제를 피하기 위해 awk를 사용하여 해결했습니다.
source="/xxx/xxx"
dest="/yyy/yyy"
n_max=`ls . | wc -l`
echo "Loop over items..."
i=1
while [ $i -le $n_max ];do
item=`ls . | awk 'NR=='$i'' `
echo "File selected for compression: $item"
tar -cvzf $dest/"$item".tar.gz "$item"
i=$(( i + 1 ))
done
echo "Done!!!"
당신은 어떻게 생각하나요?
find Downloads -type f | while read file; do printf "%q\n" "$file"; done
이것은 저에게 효과가 있으며, 거의 "깨끗"합니다.
for f in "$(find ./test -type d)" ; do
echo "$f"
done
그냥 단순한 변형 문제가....flv를 입력한 파일을 .mp3(yawn)로 변환합니다.
for file in read `find . *.flv`; do ffmpeg -i ${file} -acodec copy ${file}.mp3;done
모든 Macintosh 사용자 플래시 파일을 재귀적으로 찾아 오디오(복사본, 트랜스코드 없음)로 변환...위에서 언급한 것과 같습니다. 단순히 파일을 위한 것이 아니라 읽기입니다.탈출할 것입니다.
언급URL : https://stackoverflow.com/questions/301039/how-can-i-escape-white-space-in-a-bash-loop-list
'code' 카테고리의 다른 글
를 사용하여 프로그램이 시스템 트레이에 최소화되도록 하는 가장 쉬운 방법입니다.NET 4 (0) | 2023.04.28 |
---|---|
@SuppressLint 또는 @TargetApi 중 더 나은 것은 무엇입니까? (0) | 2023.04.28 |
첫 번째, 마지막, 인덱스 루프에 대한 각도 2 ng (0) | 2023.04.28 |
SQL Server 2008의 XML 필드에서 값 선택 (0) | 2023.04.28 |
관찰 가능한 컬렉션을 정렬하려면 어떻게 해야 합니까? (0) | 2023.04.28 |