在Bash脚本中编写文件

13

我是新手,但我正在尝试编写一个Bash脚本,实现以下功能:

write_to_file()
{
 #check if file exists
 # if not create the file
 # else open the file to edit
 # go in a while loop
 # ask input from user 
 # write to the end of the file
 # until user types  ":q"

 }

如果有人能指出相关文献,我将不胜感激。谢谢。


3
嗯,文学作品将是“人类宣言”。 - paddy
6
“man bash”更多是一本参考手册,对于初学者来说有点具有挑战性。我认为Fraz需要一个教程。请尝试使用http://tldp.org/LDP/abs/html/。 - Randall Cook
1
不错的教程。如果您在教程中发布相关链接以回答Franz提出的每个要求,那将是一个很好的答案。 - paddy
1
@RandallCook дёҚеҘҪж„ҸжҖқпјҢиҜ·дёҚиҰҒиҝҷж ·еҒҡгҖӮеј•з”ЁFreenodeзҡ„#bashйў‘йҒ“дёӯзҡ„!absдәӢе®һпјҡеә”иҜҘйҒҝе…ҚдҪҝз”ЁиҮӯеҗҚжҳӯи‘—зҡ„вҖңй«ҳзә§вҖқBashи„ҡжң¬жҢҮеҚ—пјҢйҷӨйқһдҪ зҹҘйҒ“еҰӮдҪ•иҝҮж»ӨжҺүеһғеңҫдҝЎжҒҜгҖӮе®ғдјҡж•ҷдҪ еҶҷеҮәй”ҷиҜҜиҖҢдёҚжҳҜи„ҡжң¬гҖӮеҹәдәҺиҝҷдёҖзӮ№пјҢзј–еҶҷдәҶBashGuideпјҡhttp://mywiki.wooledge.org/BashGuide - Charles Duffy
4个回答

25
更新:由于这是一个关于bash的问题,你应该首先尝试这个。;)
cat <<':q' >> test.file

要理解正在发生的事情,请阅读有关bash的IO重定向heredoc语法cat命令的内容。

如上所述,有许多方法可以做到这一点。为了更详细地解释一些bash命令,我也按照您的要求准备了该函数:

#!/bin/bash

write_to_file()
{

     # initialize a local var
     local file="test.file"

     # check if file exists. this is not required as echo >> would 
     # would create it any way. but for this example I've added it for you
     # -f checks if a file exists. The ! operator negates the result
     if [ ! -f "$file" ] ; then
         # if not create the file
         touch "$file"
     fi

     # "open the file to edit" ... not required. echo will do

     # go in a while loop
     while true ; do
        # ask input from user. read will store the 
        # line buffered user input in the var $user_input
        # line buffered means that read returns if the user
        # presses return
        read user_input

        # until user types  ":q" ... using the == operator
        if [ "$user_input" = ":q" ] ; then
            return # return from function
        fi

        # write to the end of the file. if the file 
        # not already exists it will be created
        echo "$user_input" >> "$file"
     done
 }

# execute it
write_to_file

1
@Fraz 真的很有趣!:) 很好的问题。我只需要跟随你的评论。 - hek2mgl
1
while循环之前,您不需要任何那些东西。 >>已经遵守了正确的语义。 - Carl Norum
2
[ "$foo" == "bar" ] 不符合 POSIX 标准;POSIX sh 只允许在 [ ] 中使用 =... 如果你不打算与 POSIX 兼容,应该使用 [[ ]](它更强大且更少出错)。 - Charles Duffy
@CharlesDuffy 感谢您的建议。我会阅读相关内容,可能会更新这些示例。 - hek2mgl
@CarlNorum 是的,没错。请看我的更新。我只是想展示一下文件存在性测试的方法。 - hek2mgl

6

带有基本参数检查的示例:

write_to_file()
{
    while [ "$line" != ":q" ]; do
        read line
        if [ "$line" != ":q" ]; then
            printf "%s\n" "$line" >> "$1"
        fi  
    done
}

if [ "$#" -eq 1 ]; then
    write_to_file "$1"
else
    echo "Usage: $0 FILENAME"
    exit 2
fi

或者使用可能不太为人知的until结构,这个函数可以写得更加简洁:

# append to file ($1) user supplied lines until `:q` is entered
write_to_file()
{
    until read line && [ "$line" = ":q" ]; do
        printf "%s\n" "$line" >> "$1"
    done
}

不要在 [ ] 中使用 ==,因为它不兼容 POSIX(兼容的语法只有单个 =),也没有使用非 POSIX 的 [[ ]] 扩展所提供的额外功能和安全性。 - Charles Duffy
此外,touch "$1"write_to_file "$1"; 引号是必须的,以避免字符串分割和全局扩展。 - Charles Duffy
1
此外,对于像-e foo这样的行,echo $line >> $1不会正常工作(-e将被视为echo参数),并且会折叠空格("foo bar"将变为"foo bar")。 - Charles Duffy
@CharlesDuffy,感谢您的批评;我希望我已经解决了您提出的所有提示。 - miku
@CharlesDuffy:添加了一个更简洁的版本,使用 until。 (miku 闪开 :) - miku
显示剩余2条评论

2
这个快速示例应该可以帮助您入门:

while true
do
    read INPUT
    if [[ "${INPUT}" == :q ]]
    then
        return
    fi
    echo "${INPUT}" >> file
done

还不错。一个小的改进可能是在循环开始时只打开 file 一次,而不是每次准备写入另一行时重新打开它。 - Charles Duffy
顺便提一下,更大的正确性错误是未在传递${INPUT}给echo时加引号。printf '%s\n' "$INPUT"会更理想,但即使是echo "$INPUT"也比当前情况好;因为当前情况下,输入*会被替换为文件列表,相邻多个空格的制表符和行会被压缩等。 - Charles Duffy
1
是的。安全第一,这很重要。修复。测试也应该这样做。 - Carl Norum
1
好的,这个测试是安全的;[[ ]](不像[ ])隐式地防止字符串分割或通配符扩展。 - Charles Duffy
1
[[ ]] 是一种特殊的语法。引号在其中真正是可选的。(如果您有更多关于此主题的疑问,欢迎加入 Freenode 的 #bash 频道)。 - Charles Duffy
显示剩余2条评论

2
这里有几种解决方案在过度努力地工作。只需执行以下操作:
write_to_file() { sed '/^:q$/q' | sed '$d' >>"$1"; }

第一个参数是文件名。也就是说,调用它的方式为:

write_to_file test.file

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接