#!/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 "
在其上运行,它会在前面添加一行,例如“输入 abc ”这三行中的每一行。因此,您有一个如下所示的文件:
input abc
input abc
input abc
(你看不到它,但末尾有一个空行。)他们,你运行sed -i -e 's/^/ /'
,它会在前面添加四个空格每一个行(包括空白行):
input abc
input abc
input abc
然后,你运行sed -i '/^[[:space:]]*$/d'
,它实际上做了你所期望的事情——它删除了除了空格之外什么都没有的行,留下:
input abc
input abc
input abc
然后,在循环的下一次迭代中,运行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
...ETC。这不是做你想做的事根本不。
如果我明白你想要做什么,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
如果您不需要打印“行号...”内容,或者可以将其发送到标准错误输出而不是标准输出(通常是您应该发送状态信息的位置,即使它不是实际错误),你可以让它变得更简单:
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
) 执行此操作,因为在这种情况下,您依赖于 shell 将变量的值拆分为单词...这不是特别安全。你真的想循环吗字在输入文件中,或者你想循环线反而?如果您想要线条,请不要使用该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
.但不是在 shell 循环中,只是让sed
自己扫描输入文件,input
在每一行中添加“”:
sed 's/^/ input /' "$FILE1" >"$FILES"
无论如何,您当前正在将 $FILE1 复制到一个字面名为“FILE2”的文件,然后将其读入名为value
... 的变量中,而这些都不是必需的;无论你做什么都应该直接从原始文件中读取。
另请注意:使用小写或混合大小写的变量名称,而不是全部大写的名称。有一堆全大写名称对 shell 和/或其他工具具有特殊含义,如果您错误地使用其中一个,可能会发生奇怪的事情。