我已将问题隔离到以下代码段:
LATEST_FILE_NAME=''
运行脚本时,会将空字符串分配给ksh
;但是当使用$LATEST_FILE_NAME
运行时,脚本会正确地将值分配给变量sh
。这又会影响$FILE_LIST_COUNT
。tee
命令时,ksh脚本正常工作并正确地将值赋给变量$LATEST_FILE_NAME
。(cd $SOURCE_FILE_PATH; ls *.txt 2>/dev/null) | sort -r > ${SOURCE_FILE_PATH}/${FILE_LIST} | tee -a $LOG_FILE_PATH
请考虑:
1。源代码:script.sh
#!/usr/bin/ksh
set -vx # Enable debugging
SCRIPTLOGSDIR=/some/path/Scripts/TEST/shell_issue
SOURCE_FILE_PATH=/some/path/Scripts/TEST/shell_issue
# Log file
Timestamp=`date +%Y%m%d%H%M`
LOG_FILENAME="TEST_LOGS_${Timestamp}.log"
LOG_FILE_PATH="${SCRIPTLOGSDIR}/${LOG_FILENAME}"
## Temporary files
FILE_LIST=FILE_LIST.temp #Will store all extract filenames
FILE_LIST_COUNT=0 # Stores total number of files
getFileListDetails(){
rm -f $SOURCE_FILE_PATH/$FILE_LIST 2>&1 | tee -a $LOG_FILE_PATH
# Get list of all files, Sort in reverse order, and store names of the files line-wise. If no files are found, error is muted.
(cd $SOURCE_FILE_PATH; ls *.txt 2>/dev/null) | sort -r > ${SOURCE_FILE_PATH}/${FILE_LIST} | tee -a $LOG_FILE_PATH
if [[ ! -f $SOURCE_FILE_PATH/$FILE_LIST ]]; then
echo "FATAL ERROR - Could not create a temp file for file list.";exit 1;
fi
LATEST_FILE_NAME="$(cd $SOURCE_FILE_PATH; head -1 $FILE_LIST)";
FILE_LIST_COUNT="$(cat $SOURCE_FILE_PATH/$FILE_LIST | wc -l)";
}
getFileListDetails;
exit 0;
2。使用shell时的输出 sh script.sh
:
+ getFileListDetails
+ rm -f /some/path/Scripts/TEST/shell_issue/FILE_LIST.temp
+ tee -a /some/path/Scripts/TEST/shell_issue/TEST_LOGS_201304300506.log
+ cd /some/path/Scripts/TEST/shell_issue
+ sort -r
+ tee -a /some/path/Scripts/TEST/shell_issue/TEST_LOGS_201304300506.log
+ ls 1.txt 2.txt 3.txt
+ [[ ! -f /some/path/Scripts/TEST/shell_issue/FILE_LIST.temp ]]
cd $SOURCE_FILE_PATH; head -1 $FILE_LIST
++ cd /some/path/Scripts/TEST/shell_issue
++ head -1 FILE_LIST.temp
+ LATEST_FILE_NAME=3.txt
cat $SOURCE_FILE_PATH/$FILE_LIST | wc -l
++ cat /some/path/Scripts/TEST/shell_issue/FILE_LIST.temp
++ wc -l
+ FILE_LIST_COUNT=3
exit 0;
+ exit 0
第3。使用ksh时的输出 ksh script.sh
:
+ getFileListDetails
+ tee -a /some/path/Scripts/TEST/shell_issue/TEST_LOGS_201304300507.log
+ rm -f /some/path/Scripts/TEST/shell_issue/FILE_LIST.temp
+ 2>& 1
+ tee -a /some/path/Scripts/TEST/shell_issue/TEST_LOGS_201304300507.log
+ sort -r
+ 1> /some/path/Scripts/TEST/shell_issue/FILE_LIST.temp
+ cd /some/path/Scripts/TEST/shell_issue
+ ls 1.txt 2.txt 3.txt
+ 2> /dev/null
+ [[ ! -f /some/path/Scripts/TEST/shell_issue/FILE_LIST.temp ]]
+ cd /some/path/Scripts/TEST/shell_issue
+ head -1 FILE_LIST.temp
+ LATEST_FILE_NAME=''
+ wc -l
+ cat /some/path/Scripts/TEST/shell_issue/FILE_LIST.temp
+ FILE_LIST_COUNT=0
exit 0;+ exit 0
答案 0 :(得分:2)
好的,这里......这是一个棘手而微妙的问题。答案在于如何实施管道。 POSIX表示
如果管道不在后台(请参阅异步列表),shell应等待管道中指定的最后一个命令完成,并且还可以等待所有命令完成。)
请注意关键字可能。许多shell以所有命令需要完成的方式实现这一点,例如:请参阅bash联机帮助页:
shell在返回值之前等待管道中的所有命令终止。
请注意ksh联机帮助页中的措辞:
除了最后一个命令之外,每个命令都作为一个单独的进程运行; shell等待最后一个命令终止。
在您的示例中,最后一个命令是tee
命令。由于tee
没有输入,因为您之前在命令中将stdout
重定向到${SOURCE_FILE_PATH}/${FILE_LIST}
,它会立即退出。换句话说,tee
比早期的重定向更快,这意味着在您从中读取文件时,您的文件可能还没有完成写入。你可以通过在整个命令的末尾添加sleep
来测试这个(这不是一个修复!):
$ ksh -c 'ls /tmp/* | sort -r > /tmp/foo.txt | tee /tmp/bar.txt; echo "[$(head -n 1 /tmp/foo.txt)]"'
[]
$ ksh -c 'ls /tmp/* | sort -r > /tmp/foo.txt | tee /tmp/bar.txt; sleep 0.1; echo "[$(head -n 1 /tmp/foo.txt)]"'
[/tmp/sess_vo93c7h7jp2a49tvmo7lbn6r63]
$ bash -c 'ls /tmp/* | sort -r > /tmp/foo.txt | tee /tmp/bar.txt; echo "[$(head -n 1 /tmp/foo.txt)]"'
[/tmp/sess_vo93c7h7jp2a49tvmo7lbn6r63]
话虽如此,这里还有一些需要考虑的事情:
总是引用您的变量,特别是在处理文件时,以避免浮点运算,分词(如果您的路径包含空格)等问题:
do_something "${this_is_my_file}"
head -1
已弃用,请使用head -n 1
如果一行只有一个命令,则结尾分号;
是多余的......只是跳过它
LATEST_FILE_NAME="$(cd $SOURCE_FILE_PATH; head -1 $FILE_LIST)"
首先不需要cd
进入目录,只需将整个路径指定为head
的参数:
LATEST_FILE_NAME="$(head -n 1 "${SOURCE_FILE_PATH}/${FILE_LIST}")"
FILE_LIST_COUNT="$(cat $SOURCE_FILE_PATH/$FILE_LIST | wc -l)"
这称为Useless Use Of Cat,因为不需要cat
- wc
可以处理文件。您可能使用过它,因为wc -l myfile
的输出包含文件名,但您可以使用例如而是FILE_LIST_COUNT="$(wc -l < "${SOURCE_FILE_PATH}/${FILE_LIST}")"
。
此外,您还需要阅读Why you shouldn't parse the output of ls(1)和How can I get the newest (or oldest) file from a directory?。