将任意字符串移动到命令末尾

将任意字符串移动到命令末尾

我经常发现我编造了一些我想重复使用的咒语,但它太容易受到临时调整的影响而无法存储为函数。这些命令通常包含一些关键的变量组件,例如深埋在其中的文件名。我想将该组件移至命令末尾。

例如,我最新的巫术INSERT在 diff 文件中打印所有新语句的表定义:

for T in $(grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" foo.diff | sort -u) ; do docker-compose exec mysql mysqldump --no-data some_database $T | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT" | sed "s/ COMMENT .*,$/,/" | sed "s/CONSTRAINT \`\w*\` //" | sed "s/^) ENGINE.*;/);/" ; done

为了便于阅读而格式化:

for T in $(grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" foo.diff | sort -u)
  do
  docker-compose exec mysql mysqldump --no-data some_database $T
    | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT"
    | sed "s/ COMMENT .*,$/,/"
    | sed "s/CONSTRAINT \`\w*\` //"
    | sed "s/^) ENGINE.*;/);/"
done

我很可能希望将来在未调用的文件上再次使用此命令foo.diff,因此我希望该命令以文件名结尾。我的第一个倾向是将整个事情包装在一个函数中,并将文件名作为 $1 参数。

然而,当我运行它时,我很可能会进一步调整它。在这里添加一些 sed,也许在那里添加一点 awk。因此,当我Ctrl-P再次运行它时,我仍然希望整个命令都在 CLI 上。因此我决定使用一个变量:

$ FILENAME=diff-03-04.sql

这对于这个特定的示例来说是合适的,因为我今天将为每个咒语使用相同的文件,但是还有其他示例,我真的希望能够调整命令的结尾。所以这:

$ for Q in $(foo Torvalds bar) ; do baz $Q ; done

会变成类似于(但不一定完全一样)的东西:

$ for Q in $(foo SOME_MAGIC_HERE bar) ; do baz $Q ; done < Torvalds

答案1

在我看来,您似乎误解了脚本或函数的强大功能。就我个人而言,我更喜欢脚本,因为无论我使用什么交互式 shell,它们都是独立的并且可用,但函数可以做完全相同的事情。对我来说,系统范围的脚本进入/usr/local/bin,个人(垃圾)脚本进入~/bin。两者都在我的$PATH.

创建目录~/bin。将其添加到您的$PATH( export PATH="$PATH:$HOME/bin")。现在,放置在该目录中的任何可执行脚本都可以作为新命令使用。

让我们以您的例子为例。您希望文件名成为使用时选择,因此让我们将其作为脚本的第一个参数。

创建文件~/bin/tables

#!/bin/bash
file=$1
for T in $(grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" "$file" | sort -u)
  do
  docker-compose exec mysql mysqldump --no-data some_database "$T"
    | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT"
    | sed "s/ COMMENT .*,$/,/"
    | sed "s/CONSTRAINT \`\w*\` //"
    | sed "s/^) ENGINE.*;/);/"
done

使脚本可执行chmod a+x ~/bin/tables,现在您有了一个新命令。

tables foo.diff
tables another.diff

答案2

这里的每个人都在其他答案和评论中给出了很好的建议。我发现的最好的方法是将命令包装在一个函数中,并在单个命令中运行该函数:

$ _() { echo $1; } && _ beer
beer
$

此外,我已将for T in $()语法替换为cmd | while readKusalananda 建议的语法。因此最终的语法如下:

_() { grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" $1 | sort -u | while read -r T ; do docker-compose exec mysql mysqldump --no-data some_database $T | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT" | sed "s/ COMMENT .*,$/,/" | sed "s/CONSTRAINT \`\w*\` //" | sed "s/^) ENGINE.*;/);/" ; done } && _ foo.diff

为了便于阅读而格式化:

_() {
  grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" $1
    | sort -u
    | while read -r T ;
      do
      docker-compose exec mysql mysqldump --no-data some_database $T
        | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT"
        | sed "s/ COMMENT .*,$/,/"
        | sed "s/CONSTRAINT \`\w*\` //"
        | sed "s/^) ENGINE.*;/);/"
    done
}
&& _ foo.diff

此方法保留了调整我需要的命令中任何位置的能力,但可以轻松更改参数(在本例中为文件名),而无需转义命令本身中的引号。

相关内容