공백을 포함하는 파일 이름으로 작업하기 위해 배열 사용을 제안하는 Bash 스크립팅 안내서를 보았습니다. 그러나 DashAsBinSh 는 배열을 이식 할 수 없으므로 공백을 포함 할 수있는 파일 이름 목록으로 작업하는 POSIX 호환 방법을 찾고 있습니다.
아래 예제 스크립트를 수정하려고합니다. echo
foo/target/a.jar
foo/target/b.jar
bar/target/lol whitespace.jar
여기 스크립트가 있습니다
#!/usr/bin/env sh
INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"
# this would be produced by a 'ls' command
# We can execute the ls within the script, if it helps
dostuffwith() { echo $1; };
F_LOCATIONS=$INPUT
ALL_FILES=$(for f in $F_LOCATIONS; do echo `basename $f`; done)
ALL_FILES=$(echo "$ALL_FILES" | sort | uniq)
for f in $ALL_FILES
do
fpath=$(echo "$F_LOCATIONS" | grep -m1 $f)
dostuffwith $fpath
done
답변
POSIX 포탄 하나 개의 어레이를 가지고 위치 매개 변수 ( $1
, $2
, 등의 총칭에 대해 참조 "$@"
).
set -- 'foo/target/a.jar' 'foo/target/b.jar' 'bar/target/b.jar' 'bar/target/lol whitespace.jar'
set -- "$@" '/another/one at the end.jar'
…
for jar do
dostuffwith "$jar"
done
이것은 하나만 있기 때문에 불편하며 위치 매개 변수의 다른 사용을 파괴합니다. 위치 매개 변수는 함수에 국한되며 때로는 축복이며 때로는 저주입니다.
파일 이름에 줄 바꿈이 포함되어 있지 않은 경우 줄 바꿈을 구분 기호로 사용할 수 있습니다. 변수를 확장 할 때는 먼저 글 로빙을 끄고 set -f
필드 분할 문자 목록에 IFS
줄 바꾸기 만 포함되도록 설정하십시오 .
INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"
…
set -f; IFS='
' # turn off variable value expansion except for splitting at newlines
for jar in $INPUT; do
set +f; unset IFS
dostuffwith "$jar" # restore globbing and field splitting at all whitespace
done
set +f; unset IFS # do it again in case $INPUT was empty
목록의 항목을 개행 문자로 구분하면 특히 많은 텍스트 처리 명령을 유용하게 사용할 수 있습니다 sort
.
명시 적으로 필드 분할을 원할 때를 제외하고 (글로브를 끄지 않는 한 글 로빙하는 경우를 제외하고) 변수 대체에 큰 따옴표를 항상 사용해야합니다.
답변
$INPUT
변수는 개행 문자를 구분 기호로 사용 하기 때문에 파일 이름에 개행 문자가 없다고 가정합니다. 따라서 파일을 반복하고 공백을 유지하는 간단한 방법이 있습니다.
아이디어는 read
쉘 내장 을 사용하는 것입니다 . 일반적으로 read
공백이 분리되므로 공백이 끊어집니다. 그러나 설정할 수 있으며 IFS=$'\n'
대신 줄 바꿈에서만 나뉩니다. 따라서 목록의 각 줄을 반복 할 수 있습니다.
내가 얻을 수있는 가장 작은 솔루션은 다음과 같습니다.
INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"
dostuffwith() {
echo "$1"
}
echo "$INPUT" | awk -F/ '{if (!seen[$NF]++) print }' | \
while IFS=$'\n' read file; do
dostuffwith "$file"
done
기본적으로 awk
파일 이름을 기준으로 중복 제거되는 “$ INPUT”을 보냅니다 (분할 /
한 다음 마지막 항목을 이전에 보지 않은 경우 줄을 인쇄 함). 그런 다음 awk가 파일 경로 목록을 생성하면 목록 while read
을 반복 하는 데 사용합니다.