filename match based on a known file name - bash

I want a user to input the filename which could be reside at any location but the name of the file is fixed in end .i.e. abc. txt
Let suppose the the user inputs the file name as /usr/test/abc.txt which comes in second positional parameter in my script
I want to make below statement as true how can I achieve this
if [ $2 == ..../abc.txt ]
Thanks,
Ruchir

Let suppose the the user inputs the file name as /usr/test/abc.txt which comes in second positional parameter in my script
I want to make below statement as true how can I achieve this
Use this if condition using shell glob:
if [[ "/$2" == *"/abc.txt" ]]; then
echo "valid match"
fi

You can use basename to get the last component of the filename.
prompt> cat foo.sh
#!/bin/sh
if [ "abc.txt" == `basename $2` ]; then
echo "found .../abc.txt"
fi
prompt> foo.sh foo /a/b/c/abc.txt
found .../abc/txt

you could do:
if ( echo "$2" | grep 'abc.txt$' >/dev/null ) ; then ... ; else .... ; fi
or
if ( echo "$2" | grep '/abc.txt$' >/dev/null ) ; then ... ; else .... ; fi
(if you need that "/" too ?)

if [[ $2 == *"/abc.txt" ]]; then
echo "It ends with abc.txt";
fi
Why [[ ]] works compared to [ ] is explained here...
"[ ]" vs. "[[ ]]" in Bash shell

Related

check if passed arguments to bash script is same as a filename

I want to check if the argument passed while executing the script matches the prefix of a filename in my directory. I m facing binary operator expected error with my code. Does any body have any alternative approach ?
./test.sh abc
fucn_1(){
if [ -e $file_name* ] ; then
func_2
else
echo "file not found"
exit
fi
}
if [ $1 == abc ];
then
file_name=`echo $1`
fucn_1
elif [ $1 == xyz ];
then
file_name=`echo $1`
fucn_1
while running I m passing abc as the argument such that then script can then check if the filenames starting with 'abc' is present or not in the directory.
the dir has files :-
abc_1234.txt
abc_2345.txt
The glob $file_name* expands to a list of files. You ran [ -e abc_1234.txt abc_2345.txt ] which gives an error, since [ -e expects only one file, not two.
Try something like ...
#! /usr/bin/env bash
shopt -s nullglob
has_args() { (( "$#" > 0 )); }
if has_args "$1"*; then
echo "$1 is a prefix of some file or dir"
else
echo "$1 is not a prefix of any file or dir"
fi

Bash - build URL query string by parsing script command arguments

I don't use Bash very frequently but I need to work on a bit of Bash that has to make a curl request to a web service with a query string tail built from command arguments contained in the script command arguments variable $#. So if the command argument string is something like -e something -v -s somethingelse, then the query string that must be produced is e=something&v=blank&s=somethingelse.
At the moment my test script looks like this:
#!/bin/bash
set -e
echo "${#}"
query_string=""
for arg in "${#}" ; do
if [[ "${arg}" =~ "-" ]] ; then
query_string+="${arg}="
else
if [ -z "${arg}" ] ; then
query_string+="blank&"
else
query_string+="${arg}&"
fi
fi
done
echo "${query_string}" | tr -d '-'
and produces the incorrect output
e=something&v=s=somethingelse&
I'm not sure where I'm going wrong. Any suggestions would be appreciated.
How about:
#!/bin/bash
set -e
echo "${#}"
option=true
query_string=""
for arg in "${#}" ; do
if $option ; then
query_string+="${arg}="
option=false
else
if [[ "${arg}" =~ "-" ]] ; then
query_string+="blank&${arg}="
else
query_string+="${arg}&"
option=true
fi
fi
done
echo "${query_string::-1}" | tr -d '-'
Every iteration you have to check the previous arg to see if it was a switch, not a value:
#!/bin/bash
set -e
echo "${#}"
prev_arg=""
query_string=""
for arg in "${#}" ; do
if [[ $arg == -* ]] ; then
# Current arg is a switch and the previous one was also a switch
# which means the value for it is blank
if [[ $prev_arg == -* ]] ; then
query_string+="blank&"
fi
query_string+="${arg}="
else
query_string+="${arg}&"
fi
prev_arg="$arg"
done
echo "${query_string::-1}" | tr -d '-'
This produces the following output:
something -v -s somethingelse
e=something&v=blank&s=somethingelse

bash or operator with exit status

Is it possible to have two expressions in a bash if statement, using an 'or' operator, in which one of the expressions tests the exit status of grep?
For example, I want a script to process all directories in my PATH except for '.' and /home/$LOGNAME/bin. I can do it fine with two if statements, but I'd like to combine the two tests into a single statement joined by 'or'.
This is the working version (two separate if statements):
IFS=:
for VAR in $PATH ; do
if echo $VAR | grep /home/$LOGNAME/bin > /dev/null
then
echo SKIPPING YOUR OWN bin DIRECTORY \($VAR\)
elif [ "$VAR" = "." ]
then
echo SKIPPING CURRENT WORKING DIRECTORY \($VAR\)
else
echo processing $VAR
fi
done
.. which produces the following output:
SKIPPING CURRENT WORKING DIRECTORY (.)
SKIPPING YOUR OWN bin DIRECTORY (/home/bobo/bin)
processing /home/qa/utils
processing /usr/lib64/qt-3.3/bin
processing /usr/local/bin
processing /bin
processing /usr/bin
processing /usr/local/sbin
processing /usr/sbin
processing /sbin
Just a few of many failed attempts:
if [ ( echo $VAR | grep /home/$LOGNAME > /dev/null )] -o [ "$VAR" = "." ]
if [[ ( echo $VAR | grep /home/$LOGNAME > /dev/null ) ]] -o [[ "$VAR" = "." ]]
if ( echo $VAR | grep /home/$LOGNAME > /dev/null ) -o "$VAR" = "."
if ( echo $VAR | grep /home/$LOGNAME > /dev/null ) || "$VAR" = "."
The proper form for your if elif fi block can be like this. You also don't need to use an external binary command like grep.
IFS=:
for VAR in $PATH; do
if [[ $VAR == . ]]; then
echo "SKIPPING CURRENT WORKING DIRECTORY \($VAR\)"
elif [[ "$VAR" == "/home/$LOGNAME/bin"* ]]; then
echo "SKIPPING YOUR OWN bin DIRECTORY \($VAR\)"
else
echo "processing $VAR"
fi
done
If you want to do it with one line you could have:
IFS=:
for VAR in $PATH; do
if [[ $VAR != . && "$VAR" != "/home/$LOGNAME/bin"* ]]; then
echo "processing $VAR"
else
echo "SKIPPING CURRENT WORKING DIRECTORY OR YOUR OWN bin DIRECTORY \($VAR\)"
fi
done
Or
IFS=:
for VAR in $PATH; do
if [[ $VAR == . || "$VAR" == "/home/$LOGNAME/bin"* ]]; then
echo "SKIPPING CURRENT WORKING DIRECTORY OR YOUR OWN bin DIRECTORY \($VAR\)"
else
echo "processing $VAR"
fi
done
The else block is optional.
It is possible, but totally unnecessary. Just let if evaluate the exit status of grep directly:
if echo "$var" | grep -q "$HOME/bin" || test "$var" = . ; then
...
fi
or
if echo "$var" | grep -q "^$HOME"'/bin$\|^\.$'; then ...
Note that the semantics of these are slightly different, since the second requires that $HOME/bin be the entire line, but that is probably what you want. (The anchors should be in the first example, if that is the case.)
There are several ways to do this. Using your if construct, it could look something like this (although there are a couple other equally valid ways to do it):
if [[ "${VAR}" == "." ]] || grep -q /home/${LOGNAME}/bin <<< "${VAR}"
You might also consider something like this, which I think makes it a bit clearer what you're doing, and might even be less typing (it also dispenses with calling an external program, so will be slightly more efficient):
case "${VAR}" in
.|*/home/${LOGNAME}/bin*) .... ;;
*) .... ;;
esac

sh: Test for existence of files

How does one test for the existence of files in a directory using bash?
if ... ; then
echo 'Found some!'
fi
To be clear, I don't want to test for the existence of a specific file. I would like to test if a specific directory contains any files.
I went with:
(
shopt -s dotglob nullglob
existing_files=( ./* )
if [[ ${#existing_files[#]} -gt 0 ]] ; then
some_command "${existing_files[#]}"
fi
)
Using the array avoids race conditions from reading the file list twice.
From the man page:
-f file
True if file exists and is a regular file.
So:
if [ -f someFileName ]; then echo 'Found some!'; fi
Edit: I see you already got the answer, but for completeness, you can use the info in Checking from shell script if a directory contains files - and lose the dotglob option if you want hidden files ignored.
I typically just use a cheap ls -A to see if there's a response.
Pseudo-maybe-correct-syntax-example-ahoy:
if [[ $(ls -A my_directory_path_variable ) ]] then....
edit, this will work:
myDir=(./*) if [ ${#myDir[#]} -gt 1 ]; then echo "there's something down here"; fi
You can use ls in an if statement thus:
if [[ "$(ls -a1 | egrep -v '^\.$|^\.\.$')" = "" ]] ; then echo empty ; fi
or, thanks to ikegami,
if [[ "$(ls -A)" = "" ]] ; then echo empty ; fi
or, even shorter:
if [[ -z "$(ls -A)" ]] ; then echo empty ; fi
These basically list all files in the current directory (including hidden ones) that are neither . nor ...
If that list is empty, then the directory is empty.
If you want to discount hidden files, you can simplify it to:
if [[ "$(ls)" = "" ]] ; then echo empty ; fi
A bash-only solution (no invoking external programs like ls or egrep) can be done as follows:
emp=Y; for i in *; do if [[ $i != "*" ]]; then emp=N; break; fi; done; echo $emp
It's not the prettiest code in the world, it simply sets emp to Y and then, for every real file, sets it to N and breaks from the for loop for efficiency. If there were zero files, it stays as Y.
Try this
if [ -f /tmp/foo.txt ]
then
echo the file exists
fi
ref: http://tldp.org/LDP/abs/html/fto.html
you may also want to check this out: http://tldp.org/LDP/abs/html/fto.html
How about this for whether directory is empty or not
$ find "/tmp" -type f -exec echo Found file {} \;
#!/bin/bash
if [ -e $1 ]; then
echo "File exists"
else
echo "Files does not exist"
fi
I don't have a good pure sh/bash solution, but it's easy to do in Perl:
#!/usr/bin/perl
use strict;
use warnings;
die "Usage: $0 dir\n" if scalar #ARGV != 1 or not -d $ARGV[0];
opendir my $DIR, $ARGV[0] or die "$ARGV[0]: $!\n";
my #files = readdir $DIR;
closedir $DIR;
if (scalar #files == 2) { # . and ..
exit 0;
}
else {
exit 1;
}
Call it something like emptydir and put it somewhere in your $PATH, then:
if emptydir dir ; then
echo "dir is empty"
else
echo "dir is not empty"
fi
It dies with an error message if you give it no arguments, two or more arguments, or an argument that isn't a directory; it's easy enough to change if you prefer different behavior.
# tested on Linux BASH
directory=$1
if test $(stat -c %h $directory) -gt 2;
then
echo "not empty"
else
echo "empty"
fi
For fun:
if ( shopt -s nullglob ; perl -e'exit !#ARGV' ./* ) ; then
echo 'Found some!'
fi
(Doesn't check for hidden files)

bash scripting: How to test list membership

(This is debian squeeze amd64)
I need to test if a file is a member of a list of files.
So long my (test) script is:
set -x
array=$( ls )
echo $array
FILE=log.out
# This line gives error!
if $FILE in $array
then echo "success!"
else echo "bad!"
fi
exit 0
¿Any ideas?
Thanks for all the responses. To clarify: The script given is only an example, the actual problem is more complex. In the final solution, it will be done within a loop, so I need the file(name) to be tested for to be in a variable.
Thanks again. No my test-script works, and reads:
in_list() {
local search="$1"
shift
local list=("$#")
for file in "${list[#]}" ; do
[[ "$file" == "$search" ]] && return 0
done
return 1
}
#
# set -x
array=( * ) # Array of files in current dir
# echo $array
FILE="log.out"
if in_list "$FILE" "${array[#]}"
then echo "success!"
else echo "bad!"
fi
exit 0
if ls | grep -q -x t1 ; then
echo Success
else
echo Failure
fi
grep -x matches full lines only, so ls | grep -x only returns something if the file exists.
If you just want to check if a file exists, then
[[ -f "$file" ]] && echo yes || echo no
If your array contains a list of files generated by some means other than ls, then you have to iterate over it as demonstrated by Sorpigal.
How about
in_list() {
local search="$1"
shift
local list=("$#")
for file in "${list[#]}" ; do
[[ $file == $search ]] && return 0
done
return 1
}
if in_list log.out * ; then
echo 'success!'
else
echo 'bad!'
fi
EDIT: made it a bit less idiotic.
EDIT #2:
Of course if all you're doing is looking in the current directory to see if a particular file is there, which is effectively what the above is doing, then you can just say
[ -e log.out ] && echo 'success!' || echo 'bad!'
If you're actually doing something more complicated involving lists of files then this might not be sufficient.

Resources