Google

Jan 24, 2012

UNIX Interview questions and answers

Unix for software developers

1.Top 17 Unix commands Java developers use frequently 2.History commands 3.Shell scripting 4. Reading from a file
5.Purging older files 6.Splitting and archiving files 7.Emulator, SSH client 8.Unix commands for developers 9.Unix basic interview Q&A

In Core Java Career Essentials book, I had covered some of the core UNIX commands that are useful to Java developers with practical and real life examples. This blog expands on it with some handy UNIX features to complement the book.

Q. Where would you use the control operators like ";", "&&", and "||" in UNIX?
A. These control operators are used to combine different commands in a single line. There is a difference between the characters in a sense how the subsequent commands are executed. For example,

The following commands use a ";" to separate commands. This means both the commands will be executed regardless of the first command is successful (i.e. exit code of 0) or not (i.e. exit code other than 0);

$ cd Temp; echo $(pwd)

You could get an output shown below if there is folder named Temp.

/c/Temp

If the folder named Temp is not present, you will get an error and the current directory printed.

sh: cd: Temp: No such file or directory
/c


So, what if you want to only print the current directory if the first change directory command is successful? This is where the "&&" operator comes in handy.

$ cd Temp && echo $(pwd)

In the above example, the echo command will only be excuted if the change directory command is successful. If not successful, only an error will be thrown, and the current directory will not be printed. There are situations where
you might want to do the reverse. That is, execute the second command only if the first command fails. For example, make a "Temp" directory only if the change directory fails. This where the "||" operator comes in handy.

$ cd temp ||  mkdir temp && cd temp  && echo $(pwd)

If, temp directory is not found, make a new directory named temp, and if make direcory is successful, change to that directory and echo the current directory.


Q. What do you uderstand by 2>&1 in UNIX?
A. In UNIX you have STDIN, which is denoted by number 0, STDOUT, which is denoted by 1, and STDERR, which is denoted by 2. So, the above line means, the error messages go to STDERR, which is redirected to STDOUT. So, the error messages go to where ever the STDOUT goes to. For example, The following command creates a multiple directories for a maven based Java project. if the the directory creation is successful, change directory to "project" and print the directory tree structure. The STDOUT and STDERR are directed to the file named maven-project.log under the project folder.

$ mkdir -p project/{src/{main/{java,resources},test/{java,resources}}} && cd project ; find . -type  d -print  > maven-project.log



The output will be something like

.
./src
./src/main
./src/main/java
./src/main/resources
./src/test
./src/test/java
./src/test/resources


Q. What is /dev/null?
A. It is a blackhole. For example, in the earlier example, if you want to ignore error like "sh: cd: Temp: No such file or directory" being printed, you can redirect your output to /dev/null. For example

$ cd temp > /dev/null 2>&1 && echo $(pwd)

will fail silently and nothing will be printed if there is no "temp" folder. The message has gone into the blackhole. If there is a "temp" folder, the present working directory (i.e. pwd) will be printed out.

Q. How would you go about the following scenario -- You had to move to another directory temporarily to look at a file, and then move back to the directory where you were?
A. One way is to start with "/c/Temp" folder

$ cd ../projects/JMeter
$ cd ../../Temp


The better way is to use the pushd and popd commands. These commands make use of a "stack" data structure using the "Last In First Out" approach.

changes to the /c/Projects/JMeter folder and prints the stack

$ pushd ../projects/JMeter

The stack is printed as shown below.

/c/projects/JMeter /c/Temp

The /c/projects/JMeter will be popped out of the stack and the directory will change back to /c/Temp

$ popd


If you want pushd to not print the stack, you could direct the output to the black hole /dev/null as shown below.

$ pushd ../projects/JMeter > /dev/null

The above is a trivial example, but in real life, you may want to navigate between more number of directories and this stack based approach will come in very handy without having to use the "cd" command. Also, very useful in UNIX scripts. Use it astutely without having to build up a gigantic directory stack full of useless directories.


Q. In UNIX, only nine command line arguments can be accessed using positional parameters. How would you go about having access to more than 9 argumnets?
A. Using the shift command. For example, in unix, when you run a command like

$ sh test-bash.sh file1 file2 file3 file4 file5 file6 file7 file8 file9, file10, fil11

The ${0} is test-bash.sh, and ${1} is file1, ${2} file2 and so on till ${9}, which is file9. In the program, if you want to access file10 after processing file1 to file9, you need to use the "shift" command.

$ shift

All it does is move all the command line arguments to the left by 1 position. Which means the file1 will be moved out, and file2 becomes ${1} and file10 becomes ${2}. If you shift it agian, the file3 becomes ${1} and file11 becomes ${9}. In a nutshell


${#} - Total number of arguments
${0} - Command or the script name
${1},${2}, ${3} - First, second and third args respectively.
${*} - All the command line arguments starting from $1.
${@} - Same as ${*} except when it is quoted "${@}" will pass the positional parameters unevaluated. For example, echo "${@}" will print

echo "$1" "$2" ...



Q. How will you go about writing a UNIX shell script, that reads one or more data files like the one shown below and perform a particular task like logging the information in the file or making database calls to patch some data?


The test-data.txt

Server Name:Database Name:username: password
Line2-file-name1.sql
Line2-file-name2.sql
Line2-file-name3.sql


The usage of the script will be something like

$ sh test-bash.sh test-data.txt test-data2.txt test-data3.txt


A. The sample script below will be predominantly making use of the commands discussed above. If not clear, try to read and understand the above Q&As. The best way to learn is to try it out yourself. The lines starting with "#" are comments. If you do not have a UNIX environment, download a windows UNIX emularor like MSYS or CYGWIN to run it on your WINTEL platform.

The test-bash.sh.

#!/bin/bash

# usage is -->  sh Temp/test-bash.sh Temp/test-data.txt
# ${0} is  Temp/test-bash.sh 
# ${1} is  Temp/test-data.txt

echo No of arguments:  ${#}
echo Arguments are: ${*}
echo Arguments are: ${@}

#usage sub function that gets invoked by the main function.
#Echo the usage pattern and exit the script.   
usage () {
 echo Usage : $(basename ${0}) file
 exit 1
}


#log sub function that gets invoked by the main function.
log () {
 echo ${@}
 echo ${@} >> ${LOGFILE}
}


#-r means FILE exists and is readable. 
#If the file does not exists or not readable, invoke the "usage" sub routine  to print the usage
[[ -r ${1} ]] || usage


#dirname prints the directory & basename prints the file-name
echo script directory name is: $(dirname ${0})   #
echo script-name is:   $(basename ${0}) 
echo data directory name is: $(dirname ${1})
echo data-file-name is:   $(basename ${1}) 

CMDFILE=$(basename ${1})

#this will be test-data.txt.log
LOGFILE=$(basename ${1}).log

#  take the first line in the data file and
#  translate ':" to ' ' (i.e. translate colon to empty space) 
COMMAND=($(head -1 ${1} | tr ':'  ' '))

#log the first line values in the data file 
#separate with a comma
log ${COMMAND[0]},${COMMAND[1] },${COMMAND[2]}


pushd $(dirname ${1}) > /dev/null

#log an empty line
log

#log start timestamp
log BEGIN $(date)


for SQLFILE in $(sed -n '2,$p' ${CMDFILE}); do
 log  ${SQLFILE}
 # in real life execute the sql commands using an interactive SQL command. For example
 # isql -S ${COMMAND[0]} -D ${COMMAND[1]} -U ${COMMAND[2]} -P ${COMMAND[3]} < ${SQLFILE} > ${LOGFILE} 2>&1
done

#log end time stamp
log END $(date)

popd > /dev/null

# if more data files are supplied as commandline arguments shift so that second file becomes ${1} and so on
shift

#If more filenames are supplied in the commandline arguments, repeat the script for the successive filenames.
[[ ${@} ]] && ${0} ${@}



The output for


$ sh test-bash.sh test-data.txt

will be


No of arguments: 1
Arguments are: test-data.txt
Arguments are: test-data.txt
script directory name is: .
script-name is: test-bash.sh
data directory name is: .
data-file-name is: test-data.txt
Server,Name,Database

BEGIN Tue Jan 24 12:57:16 AUSEDT 2012
Line2-file-name1.sql
Line2-file-name2.sql
Line2-file-name3.sql
END Tue Jan 24 12:57:16 AUSEDT 2012

Labels:

1 Comments:

Blogger Unknown said...

Thanks a lot

7:18 PM, May 09, 2014  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home