一个衬垫将文件附加到另一个文件中,但仅在尚未添加的情况下

时间:2015-02-06 20:12:11

标签: linux bash shell awk sed

我有一个自动化流程,其中包含许多行,如下所示:

sudo cat /some/path/to/a/file >> /some/other/file

如果尚未添加/some/other/file,我想将其转换为只附加到/some/path/to/a/file的单行内容。

修改 很明显,我需要一些例子。

示例1:更新特定登录的.bashrc脚本

示例2:为不同的登录创建.screenrc

示例3:附加到/ etc / config文件的末尾

其他一些警告。该文本将添加到块(>>)中。因此,查看是否在文件末尾附近添加整个代码块应该相对简单。我试图想出一个简单的方法来确定文件是否已经附加到原始文件。

谢谢!

示例python脚本......

def check_for_appended(new_file, original_file):
    """ Checks original_file to see if it has the contents of new_file """
    new_lines = reversed(new_file.split("\n"))
    original_lines = reversed(original_file.split("\n"))
    appended = None
    for new_line, orig_line in zip(new_lines, original_lines):
        if new_line != orig_line:
            appended = False
            break
        else:
            appended = True
    return appended

5 个答案:

答案 0 :(得分:2)

也许这会让你开始 - 这个GNU awk脚本:

gawk -v RS='^$' 'NR==FNR{f1=$0;next} {print (index($0,f1) ? "present" : "absent")}' file1 file2

将告诉您“file1”中是否存在“file1”的内容。它不能告诉你为什么,例如因为您之前已将file1连接到file2的末尾。

这就是你需要的吗?如果没有更新您的问题以澄清/解释。

答案 1 :(得分:0)

编辑:Op在评论中告诉我,他想要连接的文件是bash脚本 - 这让我们回到了好的C预处理器包括后卫策略:

使用

添加每个文件
 if [ -z "$__<filename>__" ]; then __<filename>__=1; else

(当然用文件名替换<filename>)并在最后

 fi

这样,你可以在每个文件中包含脚本,并测试一次只有一次的内​​容。

答案 2 :(得分:0)

这是一种查看文件是否包含其他文件的技术

contains_file_in_file() {
    local small=$1
    local big=$2
    awk -v RS="" '{small=$0; getline; exit !index($0, small)}' "$small" "$big"
}

if ! contains_file_in_file /some/path/to/a/file /some/other/file; then 
    sudo cat /some/path/to/a/file >> /some/other/file
fi

答案 3 :(得分:0)

这对你有用吗?

sudo (set -o noclobber; date > /tmp/testfile)

noclobber可防止覆盖现有文件。

我认为它没有,因为你写过你想要附加一些东西,但这种技术可能有所帮助。

当在一个脚本中发生追加all时,请使用标志:

if [ -z "${appended_the_file}" ]; then
   cat /some/path/to/a/file >> /some/other/file
   appended_the_file="Yes I have done it except for permission/right issues"
fi

我会继续写一个function appendOnce { .. },其中包含上述内容。如果你真的想要一个丑陋的oneliner(丑陋:眼睛和同事的痛苦):

test -z "${ugly}" && cat /some/path/to/a/file >> /some/other/file && ugly="dirt"

将此与sudo结合使用:

test -z "${ugly}" && sudo "cat /some/path/to/a/file >> /some/other/file" && ugly="dirt"

答案 4 :(得分:0)

看来你想要的是一组可以作为一个单元运行的脚本段。你的方法 - 将它们组合成一个文件 - 很难维护并受到各种竞争条件的影响,使其实现变得棘手。

一种更简单的方法,类似于大多数现代Linux发行版所使用的方法,是创建一个脚本目录,比如~/.bashrc.d,并将每个块保存为该目录中的单个文件。

驱动程序(替换所有这些文件的串联)只是一次运行一个目录中的脚本:

 if [[ -d ~/.bashrc.d ]]; then
   for f in ~/.bashrc.d/*; do
     if [[ -f "$f" ]]; then
       source "$f"
     fi
   done
 fi

要从骨架目录添加文件,只需创建一个新的符号链接。

add_fragment() {
  if [[ -f "$FRAGMENT_SKELETON/$1" ]]; then
    # The following will silently fail if the symlink already
    # exists. If you wanted to report that, you could add || echo...
    ln -s "$FRAGMENT_SKELETON/$1" "~/.bashrc.d/$1" 2>>/dev/null
  else
    echo "Not a valid fragment name: '$1'"
    exit 1
  fi
}

当然,可以通过内容而不是名称来有效地索引文件。但在大多数情况下,按名称编制索引会更好,因为它对编辑脚本片段很有用。如果您使用了内容检查(例如,md5sum),您将冒着使用相同片段的旧版本和新版本的风险,这两个版本都是活动的,并且没有明显的方法来删除旧版本。

但是,将上述结构适应您可能有的任何要求和限制应该是直截了当的。

例如,如果无法使用符号链接(例如,因为骨架和实例不共享文件系统),则可以复制文件。如果文件已经存在且具有相同的内容,您可能希望避免复制,但这只是为了提高效率,如果脚本片段很小,则可能不是很重要。或者,您可以使用rsync来保持骨架和实例彼此同步;这将是一个非常可靠和低维护的解决方案。