#!/bin/bash
FILES=/tmp/files.txt
FIELDNAME=/tmp/fieldname.txt
num=$(wc -l < $FIELDNAME)
#to read fieldname.txt content
FILE1=$1
cat $FILE1 > FILE2
value=$(<FILE2)
#to create empty lines
yes '' | sed $num\q >> $FILES
#to add fieldname content into files.txt
I=0
for fieldname in $value
do
echo "Line number $((I++)) --> $fieldname"
sed -i -e "i\input $fieldname " $FILES
sed -i -e 's/^/ /' $FILES
#to remove empty lines
sed -i '/^[[:space:]]*$/d' $FILES
done
sed -i '/^[[:space:]]*$/d' $FILES
내 스크립트 이름은 script.sh이고 이것이 스크립트를 호출하는 방법입니다.
./script.sh fieldname.txt
예상되는 결과는 다음과 같습니다.
input abc
input def
input ghi
그러나 내가 얻은 출력은 정렬되지 않았으며 다음과 같이 3줄 이상입니다.
input ghi
input def
input ghi
input abc
input ghi
input def
input ghi
input abc
input ghi
input def
input ghi
input abc
답변1
작동 방식을 오해하는 것 같습니다 sed
. 파일에서 sed 명령을 실행하면 전체 파일을 읽고 편집 규칙을 적용합니다.모든줄(규칙에 적용 위치를 제한하는 "주소" 줄이 없는 경우) 따라서 귀하의 예에서는 세 개의 빈 줄만 있는 파일로 시작한 다음 sed -i -e "i\input $fieldname "
해당 파일을 실행하면 "enter abc"와 같이 파일 앞에 줄이 추가됩니다.이 세 줄은 각각. 따라서 다음과 같은 파일이 있습니다.
input abc
input abc
input abc
(안보이지만 끝에 빈줄이 있습니다.) 그들은, 당신이 실행하면 sed -i -e 's/^/ /'
앞에 공백 4개가 추가됩니다.모든줄(빈 줄 포함):
input abc
input abc
input abc
그런 다음 실행하면 sed -i '/^[[:space:]]*$/d'
실제로 예상한 대로 수행됩니다. 공백만 있는 줄을 제거하고 다음을 남깁니다.
input abc
input abc
input abc
그런 다음 루프의 다음 반복에서 run 을 실행하면 sed -i -e "i\input def "
기존 각 행 앞에 새 행이 다시 배치됩니다.
input def
input abc
input def
input abc
input def
input abc
그런 다음 sed -i -e 's/^/ /'
각 줄에 다시 4개의 공백을 추가합니다(이미 공백이 있는 줄 포함).
input def
input abc
input def
input abc
input def
input abc
...등. 이건 네가 하고 싶은 일을 하는 게 아니야별말씀을요.
당신이하려는 일을 내가 이해한다면 sed
그것은 실제로 작업에 적합한 도구가 아닙니다. 기존 파일을 편집하려고 하기보다는 새 파일을 만들어 한 줄씩 추가하고 싶은 것 같습니다. 다음과 같이 쉽게 이 작업을 수행할 수 있습니다.
: >"$FILES" # This empties the file (in case there's something there from last run)
I=0
for fieldname in $value
do
echo "Line number $((I++)) --> $fieldname"
echo " input $fieldname" >>"$FILES" # Append a line to the end of the file
done
"줄 번호..." 항목을 인쇄할 필요가 없거나 stdout 대신 stderr로 보낼 수 있는 경우(실제 오류가 아니더라도 일반적으로 상태 정보를 보내야 하는 곳) 다음을 수행할 수 있습니다. 훨씬 더 간단합니다:
I=0
for fieldname in $value
do
echo "Line number $((I++)) --> $fieldname" >&2 # The >&2 redirects to standard error
echo " input $fieldname"
done >"$FILES" # Just send *all* standard output from the loop into the file
두 경우 모두 파일 num
의 출력이나 사전 로드가 필요하지 않습니다 .yes
여기에는 겉보기에 나쁜 관행이 많이 있습니다. 우선, 변수 참조는 "$FILES"
위의 예처럼 거의 항상 큰따옴표로 묶어야 합니다. 이렇게 하면 실수로 여러 "단어"로 분할되거나 파일 이름 와일드카드로 확장되는 것을 방지할 수 있습니다. 나는 추천한다shellcheck.net이와 같은 일반적인 실수를 지적하십시오.
$value
( )를 사용하여 이 작업을 수행하지 않았다는 점에 유의하십시오. for fieldname in $value
이 경우 변수 값을 단어로 분할하기 위해 쉘에 의존하기 때문입니다... 이는 특히 안전하지 않습니다. 정말 반복하고 싶니?성격입력 파일에 있거나 루프를 원합니다.철사대신에? 줄을 원하면 해당 for ... in
구성을 사용하지 말고 read
루프를 사용하십시오.
I=0
while read fieldname
do
echo "Line number $((I++)) --> $fieldname" >&2
echo " input $fieldname"
done <"$FILE1" >"$FILES" # Read input from $FILE1, write output to $FILES
바라보다BashFAQ #001: "파일(데이터 스트림, 변수)을 한 줄씩(및/또는 필드별로) 어떻게 읽나요?"더 많은 정보를 알고 싶습니다.
@Kusalananda가 (현재 삭제된) 주석에서 지적했듯이 이 작업을 한 줄씩 수행하고 "줄 번호..." 출력이 전혀 필요하지 않은 경우 sed
셸 루프에서는 사용할 수 없습니다. 자신을 얻으십시오 sed
입력 파일을 스캔하여 input
각 줄에 ""를 추가하십시오.
sed 's/^/ input /' "$FILE1" >"$FILES"
어쨌든 현재 $FILE1을 문자 그대로 "FILE2"라는 파일에 복사한 다음 이를 value
변수라는 이름으로 읽고 있습니다. 이 중 어떤 작업도 원본 파일에서 직접 읽어야 할 필요는 없습니다.
또한 참고: 모두 대문자 이름 대신 소문자 또는 대소문자 혼합 변수 이름을 사용하십시오. 쉘 및/또는 기타 도구에 특별한 의미를 갖는 전체 대문자 이름이 많이 있으며, 그 중 하나를 잘못 사용하면 이상한 일이 발생할 수 있습니다.