for 루프가 예상한 대로 작동하지 않는 이유는 무엇입니까?
내 스크립트 파일은 다음과 같습니다(Ventura OS 13.2.1이 설치된 MAC 컴퓨터에서 zsh를 실행하고 있습니다).
#!/bin/zsh
for user in "$(cat $1)";
do
website="myWebSite.org/@/"
url=$website$user
echo "here is the url: $url"
done
여기 내 데이터 파일이 있습니다. 한 줄에 하나씩 4개의 사용자 이름이 있습니다.
cat userList.txt
user_1
user_2
user_3
user_4
나는 출력이 다음과 같을 것으로 기대합니다.
myWebSite.org/@/user_1
myWebSite.org/@/user_2
myWebSite.org/@/user_3
myWebSite.org/@/user_4
대신에 내가 얻는 결과는 다음과 같습니다.
./findusers userList.txt
here is the url: myWebSite.org/@/user_1
user_2
user_3
user_4
나는 몇 시간 동안 인터넷 검색을 해왔지만 이런 유형의 문제에 가까운 것을 찾을 수 없습니다. 쉘이 내가 볼 수 없는 일부 파일을 조작하는 것과 거의 비슷하며 for 루프의 echo 명령이 한 번만 실행되는 이유를 이해할 수 없습니다. 내 시스템에 있는 오래된 파일의 버전 문제인가요? 도움을 주셔서 감사합니다. zsh 코딩은 제 본업이 아닙니다. 감사합니다!
답변1
명령 대체를 분할해야 합니다.
for user in $(<$1)
따옴표가 없으면 기본값은 $(...)
공백, 탭, 줄 바꿈 및 널 문자로 분할되는 것입니다. Korn과 유사한 연산자는 여기에서 대신 최적화로 $IFS
사용됩니다 .$(<file)
$(cat -- $1)
줄 바꿈(일명 line f
eed)으로만 분할하려면 동일한 작업을 수행하되 인수 확장 플래그(약어로 약칭 )를 IFS=$'\n'
사용하거나 사용하십시오 .f
ps[\n]
for user in ${(f)"$(<$1)"}
IFS 분할을 방지하기 위해 따옴표를 기록한 다음 f
개행 문자에서 분할할 플래그를 기록하십시오.
while read
루프를 사용할 수도 있습니다 .
while IFS= read -ru3 user; do
...
done 3< $1
이전 방법과의 한 가지 차이점은 빈 줄을 건너뛰지 않는다는 것입니다.
또한 마지막 줄 바꿈 뒤의 문자가 있으면 건너뛰지만 이러한 문자는 텍스트 파일에서 허용되지 않습니다.
전체 파일을 메모리에 저장하는 것을 방지하지만, 반면에 각 파일은 read
줄을 구분하는 개행 문자 이상을 읽지 않도록 해야 하므로 파일을 한 번에 1바이트씩 읽습니다.
그리고:
for user in "${(f@)$(<$1)}"
또는:
IFS=$'\n\n'
for user in $(<$1)
명령 대체 표시줄로 빈 줄(후행 공백 줄 제외)을 남겨 둡니다.모두후행 개행 문자.
모든 줄을 배열로 읽으면서 빈 줄과 마지막 개행(있는 경우) 뒤의 바이트로 구성된 비줄을 고려하고 이를 반복하는 것은 매우 어색해 지므로 도우미 함수를 사용할 수 있습니다.
lines() {
local ret
reply=( "${(@f)$(cat -- "$@"; ret=$?; echo .; exit $ret)}" )
ret=$?
reply[-1]=( ${reply[-1]%.} )
return $ret
}
lines myfile &&
for line in "$reply[@]"; do
something with "$line"
done
또한 echo
임의의 데이터 출력은 피해야 하며( 의 경우에는 zsh
실제로 사용할 수 있지만) 다른 쉘이나 Korn 쉘과 마찬가지로 사용하는 것이 가장 좋습니다 echo -E - $data
.printf '%s\n' "$data"
print -r -- "$data"
1 다른 POSIX 유사 셸(예: bash)과 달리 zsh에는 기본적으로 결과가 와일드카드의 영향을 받는 결함이 없으므로 거기 에 set -o noglob
// 같은 것을 가질 필요가 없습니다 .sh
bash
ksh
답변2
당신이 말하길(댓글에서), 입력 파일의 각 줄을 가져와 URL 앞에 URL을 추가한 다음 에 대한 호출에 사용하려고 합니다 curl
.
curl
아마도 가장 좋은 방법은 양식에 몇 줄로 구성 파일을 작성하는 것입니다.url
url = http://some/url
그런 다음 해당 파일을 단일 호출로 전달합니다 curl
.
이것을하기 위해:
curl --config <( sed 's|^|url = http://example.com/|' file )
line.out
방문한 각 URL의 출력을 이름이 지정된 파일 ( line
파일에서 읽은 행이 있는 위치) 에 저장하려면 output
각 URL에 대해 하나의 명령문을 삽입하기만 하면 됩니다.
GNU를 사용하는 방법은 다음과 같습니다 sed
.
curl --config <( sed 's|.*|url = http://example.com/&\noutput = &.out|' file )
또는 다음을 사용하십시오 awk
.
curl --config <( awk '{ printf "url = http://example.com/%s\noutput = %s.out\n", $0, $0 }' file )
마지막 두 명령은 입력 파일의 줄에 간단한 단어가 포함되어 있다는 것을 알고 있다고 가정합니다. 문자열에 절대 또는 상대 경로 이름이나 curl
유틸리티별 패턴이 포함되어 있는 경우 먼저 삭제해야 할 수도 있습니다.
답변3
또한 for 루프에서 파일을 읽는 문제가 발생했습니다.
이를 위해 while 루프를 사용합니다.
FILE="some_items.txt"
LINES=$(cat $FILE|wc -l)
INDEX=0
while [ $INDEX -lt $LINES ]
do
LN=$((INDEX + 1))
ITEM="$(cat $FILE|head -n $LN|tail -n 1)"
echo "current item is $ITEM"
INDEX=$((INDEX + 1))
done
이것은 zsh, bash 및 sh에서 작동합니다.