CentOSThis forum is for the discussion of CentOS Linux. Note: This forum does not have any official participation.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Environment:
CentOS Linux release 7.9.2009 (Core)
tr (GNU coreutils) 8.22
Problem Description:
The tr command utility is used in several of our scripts and it has worked without issue for several years and is currently working in the "primary" production site. During our business continuity exercise we migrate our processing to an alternate site. During the period of the exercise, errors were encountered with the scripts that utilize the tr utility command. The errors were caused by the tr utility failing to translate the characters in a variable from uppercase to lowercase.
Further investigation revealed that the tr command worked within a script correctly in the alternate site if executed from the command line but failed if invoked from the cron service or other service utility.
The example below contains the script that was used to verify this condition along with the debug log from an execution via the command line and the execution results from a crontab service call. The results show the tr command translation of the "CLIENT" variable from uppercase to lowercase. The command line execution is successful while the crontab entry attempt shows "tr y y" in the debug output.
This condition does not exist in primary site and both sites are running the same version of CentOS as well as the same versions of the tr utility.
***** Test Script ******
#!/bin/bash
set -x
numParms=$#
if [ ${numParms} -ge 2 ] ; then
ENV=`echo ${2} | tr [A-Z] [a-z]`
fi
CLIENT=${1}
CLIENT_LC=`echo ${CLIENT} | tr [A-Z] [a-z]`
echo "Input parameter 1 [${1}] : Environment variable [${ENV}]"
if [ "${ENV}" == "tst" ]; then
echo "Test environment variable detected"
elif [ "${ENV}" == "prd" ]; then
echo "Production environment variable detected"
else
echo "Invalid environment parameter passed: ${ENV}"
fi
echo "Client Name [${CLIENT}] Lowercase Client Name [${CLIENT_LC}]"
Options are A. find out why "tr" is not behaving correctly. B. eliminate the use of "tr".
A. There are several things I would check to troubleshoot the behavior, but I would start with examining these things:
#1 the environment as set under CRON. Since you have not set environment variable directly in the script, it is possible that there are differences that pertain. LANG is one example of a variable of interest.
#2 I would check for "tr" executibles and ensure that there is only one, or that the specific one desired is the only one addressed by the script no matter how called. Setting PATH in the script is one way, but calling external applications using the full path is another.
B. since you are using bash as the script, and all you are doing is changing case, why call "tr". Bash string handling can handle this without an external call for more reliable behavior (although LANG still needs to be set properly) with fewer cycles and fewer IO operations. It is lightly covered in the bash man pages, but there are MANY web pages with additional examples. See https://linuxhandbook.com/bash-strings/ for one.
It looks like: tr [A-Z] [a-z] is replaced (tr y y). That means you have a file named y in the directory where this script was executed (or something similar). You need to use shellcheck to check your script and to avoid situations like this.
In general you must use quotation, like: tr '[A-Z]' '[a-z]'. But as it was mentioned you can replace this tr in your case with a more efficient solution.
As I noted in my initial submission; the tr command is working fine in the primary production environment from all other service calls including cron. The variable being translated is being passed as a parameter to the script so there aren't any directory files involved in the issue. I understand that there are alternatives to the use of the tr command but that does not provide the an answer for why the inconsistent execution between invoking the command via a service call and invoking it via the command line.
I already exhausted the usual suspects such as whether there were other instances of the tr command residing elsewhere.
The one item the was suggested regarding the environment setting for cron, I have not investigated and will look into that.
1. Read man tr more carefully.
2. Pay more attention to the debug output you are receiving.
The tr command is consistently doing what it is told in all situations, but since you have unquoted shell metacharacters, tr is receiving different arguments from the shell when in a directory where those metacharacters become relevant. i.e. If your command uses brackets, you MUST quote/escape them to prevent shell interpretation, but the syntax you are using is incorrect and that it works is a coincidence.
You want either "tr A-Z a-z" or "tr '[:upper:]' '[:lower:]'"
Use ShellCheck to identify other issues which may occur.
It appears that the parameters, as passed during the cronjob on this particular server, do need to be individually quoted. I ran the command directly from a crontab entry and, lo and behold, the tr command complained when the parameters passed were not quoted and was successful after adding the quotes to the parameters to the tr command.
I also updated my test script and added the quotes around the tr parameters and it also worked. So, the mystery is solved even though on the primary production server the issue is not present.
Thank you all for providing feedback. It did provide me some alternative avenues to explore.
It appears that the parameters, as passed during the cronjob on this particular server, do need to be individually quoted.
This statement is wrong. When unquoted the shell will try to evaluate it before execution, so the result will depend on that evaluation.
You can check it if you execute set -xv before those thest commands:
Using the bash shell internals in referenced (linked) in #2, you avoid interpretation of parameters that could detect external objects during the execution. By working directly and only upon the strings already in the environment using only the internal tools you avoid not only the external call, but also any chance of that interpretation addressing outside the script for that operation. This makes the script more robust, more correct, and generally faster.
Of course, one COULD recode the entire thing in PERL or another more powerful tool than the shell to obtain similar advantage, but when you already have a solution in bash that only needs the use of tr corrected that seems ill advised. Just using modern bash properly should suffice to solve the immediate issue, and avoid any future issues that might results from vulnerable tr calls, tr behavior, or tr behavior changes.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.