当前位置: 首页 > 知识库问答 >
问题:

如何在shell脚本中延迟命令替换?

诸龙野
2023-03-14

我有一个bash脚本,简而言之,它通过其他命令生成文件(工作正常),然后在脚本的后面,我对生成的文件执行wc命令。我的问题是我在wc命令上使用命令替换,当我执行脚本时,它会立即执行此替换,而不是等待脚本中较早生成的文件。我有什么选择?

脚本是一个shell程序,用于运行Oracle SQLLoader以将数据加载到Oracle表中。SQLLoader命令生成一个包含拒绝记录的文件,我正在尝试对其进行字数计算。这是我的代码:

#!/bin/sh

#   Set variables

program_name="My Program Name"
input_dir="/interface/inbound/hr_datafile"
log_dir="/interface/inbound/log"
bad_dir="/interface/inbound/hr_bad"
archive_dir="/interface/inbound/hr_archive"
input_base="Import_20171213"
input_ext="csv"

control_file="data_loader.ctl"

exit_status=0
d=`date "+%Y%m%d"`
t=`date "+%H%M"`


#   Check if data file exists, count records

if [ -f ${input_dir}/${input_base}*.${input_ext} ]; then
    data_file_name=`ls -1rt ${input_dir}/${input_base}*.${input_ext} | head -1 | cut -c 32-100`
    data_file_base=${data_file_name%.*}
    echo "Data file name: " ${data_file_name}
    echo "Data file base: " ${data_file_base}
    no_of_recs=`expr $(wc -l ${input_dir}/${data_file_name} | cut -c 1-8) - 1`
    echo "DEBUG no_of_recs: " ${no_of_recs}
    no_of_errs=0
else
    echo
    echo
    echo 
    echo "----------------------------- ${program_name} ------------------------------------------"
    echo "----------------------------------- Error report : ------------------------------------------------"
    echo 
    echo "Please place your Data files in the UNIX directory => "${input_dir}
    echo "${program_name} Process exiting ..."
    echo
    echo "---------------------------------------------------------------------------------------------------"
    echo
    echo
    echo
    echo
    echo 
    exit 1
fi


#   Run SQL*Loader

echo
echo "==> Loading Data...into MY_TABLE table"
echo

# Create a temporary control file to pass the data file name in
cat $XX_TOP/bin/${control_file} | sed "s/:FILENAME/${data_file_name}/g" > $XX_TOP/bin/${data_file_base}_temp.ctl

# NOTE:  The following sqlldr format is used to "hide" the oracle user name and password
sqlldr errors=100000 skip=1 control=$XX_TOP/bin/${data_file_base}_temp.ctl data=${input_dir}/${data_file_name} log=${log_dir}/${data_file_base}.log bad=${bad_dir}/${data_file_base}.bad <<-END_SQLLDR > /dev/null
apps/`cat ${DB_SCRIPTS}/.${ORACLE_SID}apps`
END_SQLLDR

exit_status=$?
echo "DEBUG exit_status " ${exit_status}    

# Remove temporary control file
rm -rf $XX_TOP/bin/${data_file_base}_temp.ctl


#   Check for Errors

if [ -f ${bad_dir}/${data_file_base}.bad ]; then
    echo
    echo "----------------------------- ${program_name} ------------------------------------------"
    echo "----------------------------------- Error report : ------------------------------------------------"
    echo
    grep 'Record' ${log_dir}/${data_file_base}.log > ${log_dir}/${data_file_base}.rec
    grep 'ORA' ${log_dir}/${data_file_base}.log > ${log_dir}/${data_file_base}.err
    paste ${log_dir}/${data_file_base}.rec ${log_dir}/${data_file_base}.err ${bad_dir}/${data_file_base}.bad
    echo
    echo "<---------------------------------End of Error Report---------------------------------------------->"
    echo

    # Count error records
    no_of_errs=$(wc -l ${bad_dir}/${data_file_base}.bad | cut -c 1-8)
    no_of_recs=$(expr ${no_of_recs} - ${no_of_errs})

    # Remove temp files
    rm ${log_dir}/${data_file_base}.rec
    rm ${log_dir}/${data_file_base}.err
    rm ${bad_dir}/${data_file_base}.bad
else
    echo "Bad File not found at ${bad_dir}/${data_file_base}.bad"
fi

if (( ${no_of_errs} > 0 )); then 
    echo "Error found in data file..."
    exit_status=1
else
    # Archive the data file if no errors
    mv ${input_dir}/${data_file_name} ${archive_dir}/${data_file_base}_$d"_"$t.${input_ext}
    echo "Data file archived to ${archive_dir}"
    exit_status=0
fi

echo
echo
echo 
echo "----------------------------- ${program_name} ------------------------------------------"
echo 
echo "Total records errored out         :" ${no_of_errs}
echo "Total records successfully read   :" ${no_of_recs}
echo "---------------------------------------------------------------------------------------------------"
echo




#   Final Exit Status



if [ ${exit_status} -eq 1 ]; then
    echo "==> Exiting process...Status : ${exit_status}"
    exit 1
fi

if条件检查中引用的文件是生成的文件,因此我检查该文件是否存在,然后在其上运行wc。我知道它执行得过早,因为这个wc错误出现在我的脚本输出中之前:

Data file name:  Import_20171213.csv
Data file base:  Import_20171213
DEBUG no_of_recs:  27

==> Loading Data...into MY_TABLE table

wc: 0653-755 Cannot open /interface/inbound/hr_bad/Import_20171213.bad.
Username:
SQL*Loader: Release 10.1.0.5.0 - Production on Thu Dec 21 12:42:39 2017

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 27
Program exited with status 2

在代码中,. bad文件上的wc命令在sqlldr部分之后执行,但日志显示在调用sqlldr之前发生的错误。

任何想法将不胜感激!谢谢!

共有1个答案

狄卓君
2023-03-14

您没有看到预期的所有输出 - 缺少调用SQL * Loader之后的任何内容 - 并且wc的错误出现在错误的位置,在用户提示之前而不是之后。但是,给出您使用的构造不应该出错 - 如果文件不存在,则if测试应停止到达该行。

问题是它没有看到heredoc的结尾。所有超出heredoc开始的命令都作为heredoc处理的一部分执行,但不会去任何地方或显示到终端(如预期的那样),并且正在评估的某些方式导致wc意外运行,即使文件不存在。您正在看到由此产生的stderr输出。

这一切都发生在SQL*Loader启动之前,因此您可以在之后看到Username:提示符。

从评论中可以看出,heredoc 结尾END_SQLLDR在实际代码中确实缩进了,这在发布的问题中没有反映出来。当您使用

来自 Linux 文档项目:

here文档最后一行的结束限制字符串必须从第一个字符位置开始。不能有前导空格。限制字符串后面的尾随空白同样会导致意外行为。空格防止识别限制字符串。

删除空格,这是该行的第一件事,将修复它。

 类似资料:
  • 问题内容: 我正在编写一个shell脚本,以自动添加新用户并更新其密码。我不知道如何获取passwd来从shell脚本中读取,而不是交互式地提示我输入新密码。我的代码如下。 问题答案: 来自“ ”: 所以你的情况 [ 更新 ]评论中提到了一些问题: 您的命令可能没有选项:按照ashawley的建议使用实用程序。 如果您使用的不是bash外壳,则“echo”可能不是内置命令,外壳将调用。这是不安全的

  • 问题内容: 如何通过外壳程序脚本执行SQL命令,以使其自动化? 我想使用外壳程序脚本恢复在SQL文件中收集的数据。我想连接到服务器并还原数据。通过SSH命令行单独执行时,该命令有效。 这是我使用的命令: 这是创建文件并将其通过管道传递到mysql 的Shell脚本代码。 正确的方法是什么? 问题答案: 您需要使用该标志来发送密码。这很棘手,因为您和密码之间必须没有空格。 如果在空格之后使mysql

  • 问题内容: 我想将要在以后使用的命令存储在变量中(不是命令的输出,而是命令本身) 我有一个简单的脚本,如下所示: 但是,当我尝试更复杂的操作时,它会失败。例如,如果我做 输出为: 知道如何将这样的命令(带有管道/多个命令)存储在变量中以备后用吗? 问题答案: 使用eval:

  • stty 命令 stty -echo #禁止将输入信息显示在终端 stty echo #允许输入信息显示在终端,默认显示 tput 命令 tput clear #清空终端 tput civis #光标不可见 tput cnorm #光标可见 read 命令 read name #读取终端输入的值并赋值给 name 变量 echo $name #输出变量值 read userna

  • 在Unix shell脚本中,我想通过if语句检查diff命令的输出是否等于0。这样我就可以相应地给出if case语句。 例如:Abc.sh 输出:

  • 问题内容: 因此,在这段代码中: 似乎在FileConverter方法尚未完成调用之前,消息对话框窗口弹出窗口的速度就太快了。我想知道JOptionPane的放置是否正确,或者是否可以将消息延迟到该方法完成处理之前? 问题答案: 您可以使用SwingWorker。 在这里看看Java教程。