EzDevInfo.com

bash-scripting interview questions

Top bash-scripting frequently asked interview questions

How get full path to target of link

If I have a symbolic link /var/opt/foo created with ln -fs /path/to/target/dir foo. How can I in a script that sees only the link get /path/to/target/dir?

What I want to achieve in the script is rm -rf /path/to/target/dir before I do ln -fs /path/to/another/dir foo.


Source: (StackOverflow)

What is the simplest way to remove lines from one file matched with lines from another file?

What's the simplest way to remove lines from one file matched with lines from another file? For example, if I have the following files:

file1.csv:

u2@domain.com

file2.csv:

1,u1@domain.com,somehash1
2,u2@domain.com,somehash2
3,u3@domain.com,somehash3

As a result I'd like to have file3.csv:

1,u1@domain.com,somehash1
3,u3@domain.com,somehash3

What's the fastest way to solve this task? These files are a few GB in size.


Source: (StackOverflow)

Advertisements

how to properly use $1 in an alias with two arguments

i have to compare a number of files and I don't want to change the command in two places all the time. so i want to create an alias in bash.

alias gd='gvimdiff $1 dir/$1'

so that i can get

gvimdiff res.tex dir/res.tex

just by typing

gd res.tex

Source: (StackOverflow)

How do I enter a literal tab character in a bash shell?

For example, I wanted to use the sort utility with the -t option to specify tab separators, but

sort -t "\t"

doesn't work.


Source: (StackOverflow)

Writing shell scripts that will run on any shell (using multiple shebang lines?)

I've just started getting deeper into shell scripting, and I've always just thrown my script in a file, marked it chmod +x and then done /path/to/script.sh and let whatever interpreter is the default have its way with it, which I assumed was zsh because that's what I used for my shell. Apparently it seems that it's just /bin/sh by default, even if I execute the script from a zsh prompt, because I started putting zsh-specific stuff in my scripts and it's failing unless I run zsh /path/to/script.sh.

To get to the point, here are my questions:

  1. Which shell executes scripts when there's no shebang line (#!/path/to/shell) at the beginning? I assume /bin/sh but I can't confirm.
  2. What is considered "best practices" in terms of writing shell scripts that will run on any platform? (ok, this is sort of open-ended)
  3. Is it possible to write a script that tries to use zsh and falls back to bash if zsh is not available? I've tried putting two shebang lines, like below, but it just errors with bad interpreter: /bin/zsh: no such file or directory out if I try it on a machine without zsh.

    #!/bin/zsh

    #!/bin/bash


Source: (StackOverflow)

Difference when using backticks in double quotes and single quotes in Bash

Why to the following two executions differ in output? (I need double quotes for variables in my eventual command)

$ sudo su -c "echo `cat /root/root_file`"
cat: /root/root_file: Permission denied
$ sudo su -c 'echo `cat /root/root_file`'
Yay, highly classified content!

Source: (StackOverflow)

How to truncate file by lines?

I have a large number of file, some of which are very long. I would like to truncate them to a certain size if they are larger by removing the end of the file. But I only want to remove whole lines. How can I do this? It feels like the kind of thing that would be handled by the Linux toolchain but I don't know of the right command.

For example, say I have a 120,000 byte file with 300-byte lines and I'm trying to truncate it to 10,000 bytes. The first 33 lines should stay (9900 bytes) and the remainder should be cut. I don't want to cut at 10,000 bytes exactly, since that would leave a partial line.

Of course the files are of differing lengths and the lines are not all the same length.

Ideally the resulting files would be made slightly shorter rather than slightly longer (if the breakpoint is on a long line) but that's not too important, it could be a little longer if that' easier. I would like the changes to be made directly to files (well, possibly the new file copied elsewhere, the original deleted, and the new file moved, but that's the same from the user's POV). A solution that redirects data to a bunch of places and then back invites the possibility of corrupting the file and I'd like to avoid that...


Source: (StackOverflow)

How to update bash on Mac OS X Yosemite

Just trying to learn bash scripting a little. My old bash version:

Bash version 3.2.53(1)-release...

I've updated my bash on mac os x yosemite with homebrew:

brew update
brew install bash

Then in terminal properties I’ve changed the standard shell path from /bin/bash to /usr/local/bin/bash (As I understand this is where the homebrew installs the updated bash).

Then I checked the result again (and seems like it's all good):

$ echo $BASH_VERSION
Bash version 4.0.33(0)-release...

But when I was trying to write a simple bash script:

#!/bin/bash
echo "Bash version ${BASH_VERSION}..."
for i in {0..10..2}
  do
     echo "Welcome $i times"
 done

THE RESULT IS:

Bash version 3.2.53(1)-release...
Welcome {0..10..2} times

INSTEAD OF:

Bash version 4.0.33(0)-release...
Welcome 0 times
Welcome 2 times
Welcome 4 times
Welcome 6 times
Welcome 8 times
Welcome 10 times

Why the Bash version changes back to old one when I'm trying to execute script in the same shell??? This just freaks me out! Please someone explain me what's my problem)))


Source: (StackOverflow)

Handle filename with spaces inside Bash-script

In my Bash-script I have to handle filenames with spaces. These are the important lines inside my script:

mp3file="/media/d/Music/zz_Hardcore/Sampler/Punk-O-Rama\ Vol.5\ \[MP3PRO\]/01\ -\ Nofx\ -\ Pump\ up\ the\ Valium.mp3"
echo "Command: mp3info -x `echo $mp3file`"
mp3info -x `echo $mp3file`

Unfortunately, the command does not work, because the filename is splitted:

mp3info: invalid option -- '\'
mp3info: invalid option -- '\'
Error opening MP3: /media/d/Music/zz_Hardcore/Sampler/Punk-O-Rama\: No such file or directory
Error opening MP3: Vol.5\: No such file or directory
Error opening MP3: \[MP3PRO\]/01\: No such file or directory
Error opening MP3: Nofx\: No such file or directory
Error opening MP3: Pump\: No such file or directory
Error opening MP3: up\: No such file or directory
Error opening MP3: the\: No such file or directory
Error opening MP3: Valium.mp3: No such file or directory

I also tried to add a custom IFS as i read on some forums:

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
# Script like above
IFS=$SAVEIFS

But this way, i'm getting the error

Error opening MP3: /media/d/Music/zz_Hardcore/Sampler/Punk-O-Rama\ Vol.5\ \[MP3PRO\]/01\ -\ Nofx\ -\ Pump\ up\ the\ Valium.mp3: No such file or directory

I tried quite a while now but i cannot get my script to work. What is strange is that if i'm running the same command that my script should create manually (echoing it inside my script) on the Shell, it actually works. But not inside my script. Any hints?


Source: (StackOverflow)

Manipulating datestamp string consistently with date format %Y%m%d

I need create log files that are essentially date stamps with prefix yp_ and suffix .log, and a manipulated day number:

$ touch yp_$(echo "$(date +%Y%m%d)-10" | /usr/bin/bc -l).log
$ ls
yp_20150912.log   # ... ok for today's date.

That's fine for today, but all hell breaks loose when the day's number is between 01 and 10 included. The result cannot be interpreted as a date stamp any longer.

E.g. just imagine that the day is the 8th of March, 2016, i.e. '20160308'. How do I code the above to make sure that subtracting 10 days will produce not '20150298' but '20150227' ? Also test yr answer with 19820103 ...

-- I looked at man date.

-- apropos date spews out 161 hits that I also reviewed.

Can somebody help with that one-liner?


Source: (StackOverflow)

messaging.sh: line 29: [: missing `]'

I don't know if this is a bad thing, or what it means. My script still seems to work fine, but should I fix it?

#!/bin/sh
#This script will send text and maybe images to other computers via ssh and scp.
#Configuration files in same folder

source /Users/jacobgarby/Desktop/messaging/messages.cfg
TIME=$(date +"%H:%M:%S")
CONNECTED[0]="mainmini@192.168.1.65"

if [ -d messages.log ]; then
    :
else
    touch messages.log
fi

read MSG

if [ "$MSG" == "!help" ]; then
    echo ; echo "!clear   Clear's your personal chat log."
    echo "!ban [usrname]    Prevents a user from entering this chat IN DEV."
else
    echo "$TIME | $USER | $MSG" >> messages.log; echo   >> messages.log; echo   >> messages.log
    tail messages.log
fi

for CONNECTION in CONNECTED; do
    echo "It works"
done

if [ "alerttype" == "notification"]; then
    osascript -e 'display notification "You have recieved a message!" with title "Message"'
else
    osascript -e 'display dialog "You have recieved a message!" with title "Message"'
fi

Source: (StackOverflow)

Suppress execution trace for echo command?

I'm running shell scripts from Jenkins, which kicks off shell scripts with the shebang options #!/bin/sh -ex.

According to Bash Shebang for dummies?, -x, "causes the shell to print an execution trace", which is great for most purposes - except for echos:

echo "Message"

produces the output

+ echo "Message"
Message

which is a bit redundant, and looks a bit strange. Is there a way to leave -x enabled, but only output

Message

instead of the two lines above, e.g. by prefixing the echo command with a special command character, or redirecting output?


Source: (StackOverflow)

Process files in a folder that haven't previously been processed

I have a series of files in a directory that I need to carry an action out on using a script. Once the action is done, then I want to keep a log that the file has been processed, so that the next time the script is run, it does not attempt to carry out the action again.

So lets say I can find all the files that should be processed like this:

for i in `find /logfolder -name '20*.log'` ; do
    process_log $i
    echo $i >> processedlogsfile
done

So I have a file containing the logs I have processed, and my goal would be to modify the for loop such that these processed logs are not processed a second time.

Doing a manual scan each time seems inefficient, particularly as the processedlogfiles gets bigger:

 if grep -iq "$i" processdlogfiles ; then continue; fi

It would be good if these files could be excluded when setting up the for loop.

Note that the OS in question is a linux derivative, a managment appliance, with a limited toolset (no attr command for example) and so no way to install additional utilities (well it is possible but not an option). Most common bash shell commands are available though.

Also, the filenames and locations of the processed files must remain where they are - they can't be altered to reflect their processed status


Source: (StackOverflow)

How to move all sibling folders into one folder?

I apologize that this seems like such a dumb question, but I can't afford to screw it up.

I have a bunch of folders like so:

/users/me/foo/oops1

/users/me/foo/oops2

/users/me/foo/oops3

/users/me/foo/oops4

/users/me/foo/bar

Unfortunately, they aren't uniformly named like that, and there are hundreds of oops folders.

I intended to copy all the oops folders into bar. Is there an easy way to move all the oops folders into bar that won't result in some kind of recursive move problem?

It took several hours to copy the files. I'm hoping that the move will be much faster.

This is on a redhat linux server by the way. I only have ssh access.

I think if I do

cd foo
mv * bar

there will be a problem.


Source: (StackOverflow)

Prefix to each output of a command on runtime

I am trying to make a modular script. I have several scripts/commands which are called from a single script.
I want to prefix the output of each separate command.

Examle:

My files are allcommands.sh / command1.sh / command2.sh

command1.sh outputs
file exists
file moved

command2.sh outputs
file copied
file emptied

allcommands.sh runs the scripts command1.sh and command2.sh

I want to prefix each output of these two scripts like this:
[command1] file exists
[command1] file moved
[command2] file copied
[command2] file emptied


Source: (StackOverflow)