我经常发现我编造了一些我想重复使用的咒语,但它太容易受到临时调整的影响而无法存储为函数。这些命令通常包含一些关键的变量组件,例如深埋在其中的文件名。我想将该组件移至命令末尾。
例如,我最新的巫术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 read
Kusalananda 建议的语法。因此最终的语法如下:
_() { 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
此方法保留了调整我需要的命令中任何位置的能力,但可以轻松更改参数(在本例中为文件名),而无需转义命令本身中的引号。