我正在尝试使用 awk
datetime=`date +\%Y\%m\%d`
logdatetime=`date +\%Y\%m\%d`
foldermonth=`date +\%B_\%Y`
folderday=`date +\%d`
inputdir="~/sboper/Standalone/fsplit/GLMS"
outputdir="~/sboper/StandAlone/input/$foldermonth"
outputdirday="~/sboper/StandAlone/input/$foldermonth/GLMS_Daily/$folderday"
awk -v outdir=$outputdirday 'BEGIN{ FS = "~" } ;{if( $12 == "A" ) filename="outdir/Customer_Create_Records.dat" ; print >> filename;close(filename)}' $inputdir/$sourcefile
awk -v outdir=$outputdirday 'BEGIN{ FS = "~" } ;{if( $12 == "M" ) filename="outdir/Customer_Modify_Records.dat" ; print >> filename;close(filename)}' $inputdir/$sourcefile
但是该变量outdir=$outputdirday
没有扩展到我的输出目录路径的值。
我已经声明了 awk 变量,并且没有在 awk 脚本中使用 shell 变量。但它仍然给我错误:cannot open Customer_Create_Records.dat
。
我这个脚本哪里出了问题?当我复制完整路径而不是“outdir”时,它创建了新文件并移动了记录,但在变量中使用时无法正常工作。如何通过 awk 在我想要的目录中创建新文件?
答案1
哇。我从哪开始呢?
- 您需要学习如何调试。 如何调试 bash 脚本?
是关于该主题的高度评价的 Stack Exchange 参考资料,由我们几位最多产的成员做出的贡献。您可以在此站点上找到其他信息,并且可以在网络上找到更多信息。例如,
- 简化。
- 摆脱
folderday
、foldermonth
和`date …`
作业;只需outputdirday
用常量值构造即可。 - 避免令人困惑的相似变量名称。例如,
outdir
等于outputdirday
,但outputdir
是不同的东西。 - 消除脚本中甚至未使用的
datetime
、logdatetime
、 和。outputdir
- 消除冗余。您显示的两个
awk
命令除了细微的差别外都是相同的。其中之一有效,其中之一失败吗?他们会以不同的方式失败吗?我不这么认为。那就不要让他们两个都看到。 - 不要使用长的八级路径名(例如,
~/sboper/StandAlone/input/$foldermonth/GLMS_Daily/$folderday/Customer_Create_Records.dat
),除非您真的真的需要。
- 摆脱
- 出于演示目的(即,向其他人演示您的问题时),请避免混淆命名约定,例如命名您的输出目录
…/input/…
。 - 出于演示目的,请尽量避免使用比屏幕更宽的行(因此人们必须滚动才能完整阅读它们)。大多数系统都有方法让您将命令和程序分成多行。
- 您的目录中是否真的有两个目录(一个称为
Standalone
,一个称为) ?StandAlone
~/sboper
- 如果最终结果不是您想要的,请找出过程中间发生的情况。显示中间值。例如,
outputdirday
。当我运行你的脚本并echo "$outputdirday"
在之前执行时awk
,我得到〜/sboper/StandAlone/input/June_2016/GLMS_Daily/08
即,因为~
在引号中,所以它没有扩展到我的主目录。我不得不将作业更改为outputdirday="$HOME/sboper/StandAlone/input/$foldermonth/GLMS_Daily/$folderday"
让它发挥作用。outdir
。你说它设置不正确,但是你尝试过打印它吗?当我这样做时,我得到的值与我得到的值相同outputdirday
。filename
。 这问题所在(部分);见下文。
- 简化。
- 当你寻求帮助时,你应该
- 如上所述,简化问题。
- 描述你的命令应该做什么。
- 显示您的输入文件的样子。
- 显示您期望的输出是什么样子。
- 确定您正在使用的软件的版本。虽然我相信我了解您的脚本出了什么问题,但我无法准确地重现您的错误(因此,我想我正在运行不同版本的
awk
)。可能不是真的很重要,但你甚至没有说出你使用的操作系统。
这是重要的部分:
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
- 如果按照我上面的建议,您已将脚本中的主要操作块分解
awk
为更短的行,您可能已经意识到它相当于{ if ( $12 == "A" ) 文件名=“outdir/Customer_Create_Records.dat” 打印>>文件名 关闭(文件名) }
作为迈克尔·维尔斯指出在他的回答,这组filename
有条件的,然后写每一个输入行至filename
无条件地。正如他建议的那样,你需要做类似的事情{ 如果($12==“A”){ 文件名=“outdir/Customer_Create_Records.dat” 打印>>文件名 关闭(文件名) } }
filename
如果按照我上面的建议,您在设置后 打印了 的值,您会发现它是outdir/Customer_Create_Records.dat
因为"outdir"
(引号中)意味着细绳o
u
t
d
i
r
,而不是价值变量outdir
.你需要做文件名 = outdir "/Customer_Create_Records.dat"
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
几乎同样重要:
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
- 您应该始终引用您的 shell 变量引用(例如,
"$outputdirday"
、"$inputdir"
和"$sourcefile"
),除非您有充分的理由不这样做,并且您确定您知道自己在做什么。这似乎不是这个问题的原因,但最终会给你带来麻烦。 - 为了清楚起见,您可能需要更改
`…`
为$(…)
- 请参阅这,这, 和这。
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
- 虽然您应该始终引用 shell 变量引用,除非您有充分的理由不这样做,但这不适用于反斜杠。仅当有理由时才应使用它们。例如,
date +%Y%m%d
和date +%B_%Y
等,工作得很好。 正如我之前所建议的,对于您似乎正在做的事情,您不需要两次
awk
调用。你可以用以下方式完成整个事情awk -v outdir="$outputdirday" ' BEGIN { FS = "~" filenameA = outdir "/Customer_Create_Records.dat" filenameM = outdir "/Customer_Modify_Records.dat" } { if ($12 == "A") print >> filenameA if ($12 == "M") print >> filenameM } ' "$inputdir/$sourcefile"
或者
awk -v outdir="$outputdirday" ' BEGIN { FS = "~" filenameA = outdir "/Customer_Create_Records.dat" filenameM = outdir "/Customer_Modify_Records.dat" } $12 == "A" { print >> filenameA} $12 == "M" { print >> filenameM} ' "$inputdir/$sourcefile"
据我所知,您
close
根本不需要这些文件;当程序退出时,文件通常会自动关闭。
答案2
你的问题对我来说不是很清楚,但我认为你可能想:
if( $12 == "A" ) {
filename="outdir/Customer_Create_Records.dat" ;
print >> filename;close(filename)
}
如果没有花括号,条件条件的“then”子句将在第一个分号处结束。因此,您可能会在定义输出文件的名称之前尝试将行写入输出文件。
答案3
问题出在我的 awk 语法和我提供给 awk 的输入文件上。 “$inputdir/$sourcefile” - 这没有扩展为单个文件名。
感谢所有发布答案的人 - 它帮助我理解错误。生成的代码如下所示(这是来自更大脚本的片段,因此我声明的所有变量可能不仅仅与该片段相关)
timestamp=`date +\%Y\%m\%d\%H\%M\%S`
logfile=/udd001/sboper/CMStandAlone/input/logs/SBSA_GLMS_CUST_$timestamp.log
datetime=`date +\%Y\%m\%d`
logdatetime=`date +\%Y\%m\%d`
foldermonth=`date +\%B_\%Y`
folderday=`date +\%d`
inputdir="/udd001/sboper/CMStandalone/fsplit/GLMS"
outputdir="/udd001/sboper/CMStandAlone/input/$foldermonth"
outputdirday="/udd001/sboper/CMStandAlone/input/$foldermonth/GLMS_Daily/$folderday"
inputfile=$( ls -1 /udd001/sboper/CMStandalone/fsplit/GLMS/GCP1_cdf_001_$datetime*.txt )
sourcefile=`basename $inputfile`
if [ ! -d "$outputdirday" ]; then
mkdir -p "$outputdirday"
fi
if [ -f "$inputdir/$sourcefile" ]
then
cp "$inputdir/$sourcefile" "$outputdirday"
echo "output directory : $outputdirday"
awk -v outdir="$outputdirday" '
BEGIN { FS = "~"
filenameA = outdir"/SBSA_Amdocs_Customer_Create_Records.dat"
filenameM = outdir"/SBSA_Amdocs_Customer_Modify_Records.dat"
}
$12 == "A" { print >> filenameA}
$12 == "M" { print >> filenameM}
' "$inputdir/$sourcefile
”
fi