这是一个简单的bash脚本,用于编译和运行单个C++文件,用于编码竞赛。
功能:
.in文件,如果有,则将其用作stdin 。problem1.cpp和problem1.in位于同一个目录中,脚本将从problem1.in重定向stdin注意:\033[32m和\033[0m是使文本变成绿色的终端颜色代码。
#!/bin/bash
# Compiles and runs .cpp code
# if there exists an .in file next to the .cpp file
# it will use that as input
if [ -z $1 ]; then
echo -e "Please choose an input file"
exit 1
fi
FILE="$1"
FILE_IN="${FILE%.*}.in"
clear
echo -e "\033[32mCompiling...\033[0m"
TMPFILE=$(mktemp /tmp/run-cpp.XXXXXXXXXX)
WARNING_FLAGS="-Wuninitialized -Wmaybe-uninitialized"
g++ $FILE -std=c++17 $WARNING_FLAGS -O3 -o $TMPFILE
if [ $? -eq 0 ]; then
echo -e "\033[32mRunning...\033[0m"
if [ -f $FILE_IN ]; then
$TMPFILE < $FILE_IN
else
$TMPFILE
fi
ERROR=$?
fi
rm $TMPFILE 2> /dev/null
exit $ERROR用法:./runcpp.sh /path/to/my-cpp-file.cpp
发布于 2020-12-10 17:37:37
#!/bin/bash
我不明白为什么要使用Bash --使用标准POSIX shell应该没有问题。
如果;那么
我建议在那里使用"$1",尽管额外的参数会导致[由于其他原因返回false。作为单个参数传递不会发出任何错误消息。
回显-e“请选择输入文件”
echo -e不是可移植的,在这里也没有必要。
FILE="$1“FILE_IN="${FILE%.*}.in”
避免为您自己的程序中的变量使用全大写名称--这些名称通常是为更改程序行为的环境变量而保留的。
清除
我认为这有点粗鲁--我们中的一些人喜欢将结果与之前的结果进行比较。如果我想在运行前清除,我可以很容易地键入。
回波-e“\033[32.\033[0m]”
别像那样嵌入终端特定的转义码!即使最近的终端支持ANSI转义,还有其他的-如果您重定向到文件,您不希望它随处可见的控制字符。使用tput为您的$TERM生成正确的转义符(以及更易读的代码)。
TMPFILE=$(mktemp /tmp/run-cpp.XXXXXXXXXX)
这不是一个描述性很强的变量名。说它是为了什么(创建的可执行文件)是更有信息的。为什么硬编码/tmp作为目录?如果设置了$TMPDIR (可能是具有每个用户临时目录的系统,或者有快速或大型临时存储的选择),则更喜欢使用set。
WARNING_FLAGS="-Wuninitialized -W或许-未初始化“
这是一套相当松懈的警告。如果您关心源的质量,请再添加几个。我建议-Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Weffc++。如果您只关心性能,那么也许-Wall -Wextra -Wno-parentheses -Warray-bounds就足够了。
由于我们只使用这个变量一次,也许我们应该内联它的使用,这样就不会触发一个Shellcheck警告,在这里我们(正确地)不用引号展开它。
g++ $FILE -std=c++17 $WARNING_FLAGS -O3 -o $TMPFILE
"$FILE"也在这里。我会写"$TMPFILE",尽管我们构建它是为了一个安全的名字。
如果;那么
反模式--只需在if之后直接使用前面的命令。或者,启用shell的-e标志,在编译失败时退出。
回声-e“\033[32 32mRunning.\033[0m]”
tput又来了。
如果;那么
再引用一遍。
$TMPFILE < $FILE\_IN else $TMPFILE fi
由于我们不使用stdin,所以可以使用stdin重定向exec,而不需要两个不同的命令。
ERROR=$?fi rm $TMPFILE 2> /dev/null
如果我们提前退出,为什么不删除临时文件呢?
出口$ERROR
如果我们将删除临时文件作为退出陷阱,则不需要存储错误。
#!/bin/sh
# Compiles and runs C++ source code. A corresponding file
# ending with .in will be used as input, if present
set -eu
if [ $# -ne 1 ] || [ -z "$1" ]
then
echo "Usage: $0 SOURCE"
exit 1
fi
executable=$(mktemp -t run-cpp.XXXXXXXXXX)
trap 'rm $executable' EXIT
green=$(tput setaf 2)
normal=$(tput sgr0)
echo "${green}Compiling...${normal}"
g++ -o "$executable" -std=c++17 -O3 \
-Wall -Wextra -Wwrite-strings -Wno-parentheses \
-Wpedantic -Warray-bounds -Weffc++ \
"$1"
echo "${green}Running...${normal}"
input=${1%.*}.in
if [ -f "$input" ]
then exec <"$input"
fi
"$executable"您也可能对我对待类似情况的方法感兴趣,它使用Make而不是shell。
发布于 2020-12-11 15:00:59
另一篇评论提出了我想要得到的大部分观点,所以我只需再补充三点。
mktemp的返回值
出于安全考虑,如果所选择的名称已经存在,mktemp将拒绝创建文件。这是为了避免安全缺陷。您可能会被保存,因为/tmp/应该始终设置粘性位,从而防止文件所有者以外的用户删除它。不过,我还是推荐这样的建筑:
TMPFILE=$(mktemp /tmp/example.XXXXXXXXXX) || exit 1另一种选择是省略输出文件名,只允许编译器在本地目录中创建a.out,完全绕过这个问题,并缩短脚本。
$?该守则包括:
g++ $FILE -std=c++17 $WARNING_FLAGS -O3 -o $TMPFILE
if [ $? -eq 0 ]; then但这可以变得更直接一点:
if g++ $FILE -std=c++17 $WARNING_FLAGS -O3 -o $TMPFILE ; then或者更好,看下一个建议。
我建议创建一些函数,比如run和compile,这样可以使脚本更容易理解。例如:
compile() {
WARNING_FLAGS="-Wuninitialized -Wmaybe-uninitialized"
g++ "$1" -std=c++17 $WARNING_FLAGS -O3 -o "$2"
}
if compile "$FILE" "$TMPFILE"; thenhttps://codereview.stackexchange.com/questions/253140
复制相似问题