I am trying to make an if-statement that says:  If a file in this directory has .PDF extension do this, otherwise do this...  And I'm having a hard time figuring out how to do this in bash. I checked here :  first but the solutions listed either don't work or give errors I don't know how to fix. Attached below is  my script. I slightly modified the script I was working on in my previous question here:  The script is below: #!/bin/bash #shebang for bourne shell execution echo &quot;Hello this is task 1 of the homework&quot;  #Initial prompt used for testing to see if script ran   #shopt allows configuration of the shell -s dotglob allows the script to run on dot-files shopt -s dotglob  #loop to iterate through each file in Task1 directory and rename them #loop runs if there is a file type of &quot;.PDF&quot; in the folder Task1, if there isn't displays that there i sn't a file of that type and terminates  if [ [ -n $(echo *.PDF) ] ] # what should I put here???   then         for file in Task1/*.PDF;         do                  mv &quot;$file&quot; &quot;${file%.PDF}.pdf&quot;                 echo &quot;$file has been updated&quot;         done else                 echo &quot;No files of that type...&quot; fi ~             **Edit 1: ** As per Ipor Sircer's answer below I changed my script to the following: #!/bin/bash #shebang for bourne shell execution echo &quot;Hello this is task 1 of the homework&quot;  #Initial prompt used for testing to see if script ran   #shopt allows configuration of the shell -s dotglob allows the script to run on dot-files shopt -s dotglob  #loop to iterate through each file in Task1 directory and rename them #loop runs if there is a file type of &quot;.PDF&quot; in the folder Task1, if there isn't displays that there isn't a file of that type and terminates  if [ ls -1 *.PDF|xargs -l1 bash -c 'mv $0 ${0%.PDF}.pdf' ] then         for file in Task1/*.PDF;         do                  mv &quot;$file&quot; &quot;${file%.PDF}.pdf&quot;                 echo &quot;$file has been updated&quot;         done else                 echo &quot;No files of that type...&quot; fi  I get the following errors:  Hello this is task 1 of the homework ./Shell1.sh: line 12: [: missing `]' mv: cannot stat ']': No such file or directory No files of that type...  Edit 2 As per  Eric Renouf's comment fixing the spacing gives me the following script: #!/bin/bash #shebang for bourne shell execution echo &quot;Hello this is task 1 of the homework&quot;  #Initial prompt used for testing to see if script ran   #shopt allows configuration of the shell -s dotglob allows the script to run on dot-files shopt -s dotglob  #loop to iterate through each file in Task1 directory and rename them #loop runs if there is a file type of &quot;.PDF&quot; in the folder Task1, if there isn't displays that there isn't a file of that type and terminates  if [[ -n $(echo *.PDF) ]] then         for file in Task1/*.PDF;         do                  mv &quot;$file&quot; &quot;${file%.PDF}.pdf&quot;                 echo &quot;$file has been updated&quot;         done else                 echo &quot;No files of that type...&quot; fi  However if I run it twice I see the following:  Hello this is task 1 of the homework mv: cannot stat 'Task1/*.PDF': No such file or directory Task1/*.PDF has been updated  Why don't I just see the else echo since there are no files of type .PDF in the folder anymore?
38090
I am trying to write an if statement to test whether there are any files matching a certain pattern. If there is a text file in a directory it should run a given script.  My code currently:  if [ -f /*.txt ]; then ./script fi   Please give some ideas; I only want to run the script if there is a .txt in the directory.
77200
Any idea why echo statement is being executed in both scenarios?  Outputs it worked:  #!/bin/bash  rizwan='' if [ -n $rizwan ]; then   echo "it worked" fi   Replace -n with -z, and it outputs it worked when expecting no output:  #!/bin/bash  rizwan='' if [ -z $rizwan ]; then   echo "it worked" fi
65652
In bash, I know that it is possible to write a for loop in which some loop control variable i iterates over specified integers.  For example, I can write a bash shell script that prints the integers between 1 and 10: #!/bin/bash  for i in {1..10} do  echo $i done  Is it possible to instead iterate over a loop control variable that is a string, if I provide a list of strings?  For example, suppose that I have a string fname that represents a file name.  I want to call a set of commands for each file name.  For example, I might want to print the contents of fname using a command like this: #!/bin/bash  for fname in {&quot;a.txt&quot;, &quot;b.txt&quot;, &quot;c.txt&quot;} do  echo $fname done  In other words, on the first iteration, fname should have the value fname=&quot;a.txt&quot;, while on the second iteration, fname should have the value fname=&quot;b.txt&quot;, and so on.  Unfortunately, it seems that the above syntax is not quite correct.  I would like to obtain the output:  a.txt b.txt c.txt  but when I try the above code, I obtain this output:  {a.txt, b.txt, c.txt}  Can you please help me determine the correct syntax, so that I can iteratively change the value/contents of the variable fname?  Thank you for your time.
2953
I have a bash script which I use to compile a file with pdflatex twice (to make sure it sorts out references properly, etc.). This is the 'latexbuild' script I use:  module load ctan pdflatex --shell-escape --interaction=nonstopmode $1 bibtex $1 pdflatex --shell-escape --interaction=nonstopmode --interaction=batchmode $1   I would then call this script with latexbuild test.tex. It produces a lot of output which I would like to supress, except for the error messages which I'd like to see. Is there any way to only allow error messages to be displayed?
23751
I want to create a simple bash-script that checks whether a directory contains all the files whose names contain numbers from 1 to N.  # Creating some files for testing $ cd /tmp/ $ mkdir test $ touch test/a01x.dat $ touch test/b02y.dat  # Display dir contents $ ls test/*{01,02}* test/a01x.dat  test/b02y.dat   But using seq command to generate numbers results in the following:  $ ls test/*{$(seq -s , -f "%02g" 1 2)}* ls: cannot access 'test/*{01,02}*': No such file or directory   I understand that running the command by surrounding the path with single quotation marks must lead to the error because the wildcards don't expand  $ ls 'test/*{01,02}*'   But I didn't use them. What is the problem?
105129
I have a bash script file, which is put under some directory added to $PATH so that I can call the script from any directory.  There is another text file under the same directory as the script. I wonder how to refer to the text file in the script?  For example, if the script is just to output the content of the text file, cat textfile won't work, since when calling the script from a different directory, the text file is not found.
16228
Suppose a shell script (/bin/sh or /bin/bash) contained several commands.  How can I cleanly make the script terminate if any of the commands has a failing exit status?  Obviously, one can use if blocks and/or callbacks, but is there a cleaner, more concise way?  Using &amp;&amp; is not really an option either, because the commands can be long, or the script could have non-trivial things like loops and conditionals.
53046
I have files in a directory (/home/user/example) that I need to verify and match. Each file has a control and data file. I want to check if for each file there is a corresponding file of the other. For example, if example.ctl has a match with example.out or example.out has a corresponding file with example.ctl.   I had written a nested for loop and  with many if else statements. But this seemed to be far too complex for a basic check like this. I wanted to see if anyone had a better solution.   Example files in directory:  example.ctl example.out   example_1.ctl example_1.out   example_2.ctl example_2.out
118021
I want to make small bash scripts that will automate some stuff for me in new machines.  The only thing I still do manual is creating files with vi and pasting the text on the file.  How can I generate file X with "text i need here" inside it on bash? Without having to press enter, overwrite files if necessary and also create directories as needed?  Thanks  Example : Replacing a default sshd_config file with my version and creating a file with my public SSH key inside it. Generating another .sh file on-the-fly. Stuff like that.
75153
There are some utilities that accept a -- (double dash) as the signal for "end of options", required when a file name starts with a dash:  $ echo "Hello World!" &gt;-file  $ cat -- -file Hello World!  $ cat -file                      # cat - -file fails in the same way. cat: invalid option -- 'f' Try 'cat --help' for more information.   But some of those utilities don't show such an option in the manual page.  The  doesn't document the use (or validity) of a -- argument in any of the OS'es. This is not meant to be a Unix - Linux flame war, it is a valid, and, I believe, useful concern.  Neither cat, mv, ed (and I am sure many others) document such an option in their manual page that I can find.  Note that ./-file is a more portable workaround to the use of --. For example, the source (dot) command (and written as .) doesn't (generally) work well with an -- argument:  $ echo 'echo "Hello World!"' &gt;-file  $ . ./-file Hello World!  $ . -file ksh: .: -f: unknown option ksh: .: -i: unknown option ksh: .: -l: unknown option ksh: .: -e: unknown option Usage: . [ options ] name [arg ...]  $ . -- -file         # works in bash. Not in dash, ksh, zsh. ksh: .: -file: cannot open [No such file or directory]
82155
This is my script:  #!/bin/bash hd='pwd' cd $hd   When I try to run it, it fails with:  line 3: cd: $'pwd\r\r': No such file or directory   What is going on?
13427
I want to create an array of dates and compare it to today's date if it matches then execute test.sh file otherwise exit the loop in bash script. I have this so far:  #!/bin/bash now=$(date +%Y-%m-%d) array=['2016-03-02','2015-01-02'] for i in "${array[@]}" do     if [ $now -eq $i ]; then         bash test.sh     else         echo "error"     fi done   please write the correct way to do this..
34727
I want to test if a directory doesn't contain any files. If so, I will skip some processing.  I tried the following:  if [ ./* == "./*" ]; then     echo "No new file"     exit 1 fi   That gives the following error:  line 1: [: too many arguments   Is there a solution/alternative?
94743
I have a bash script like this  export pipedargument="| sort -n" ls $pipedargument   But it gives the error  ls: |: No such file or directory ls: sort: No such file or directory   It seems to be treating the contents of "| sort -n" as just an argument passed to ls.   How can I escape it so that it's treated as a regular piped command?   I'm trying to conditionally set the $pipedargument. I guess I could just conditionally execute different versions of the command but still wondering if there's a way to make this work like above?
15319
While answering  it struck me that it seems find, in the following example, potentially would process files multiple times:  find dir -type f -name '*.txt' \     -exec sh -c 'mv "$1" "${1%.txt}_hello.txt"' sh {} ';'   or the more efficient  find dir -type f -name '*.txt' \     -exec sh -c 'for n; do mv "$n" "${n%.txt}_hello.txt"; done' sh {} +   The command finds .txt files and changes their filename suffix from .txt to _hello.txt.  While doing so, the directories will start accumulating new files whose names matches the *.txt pattern, namely these _hello.txt files.  Question: Why are they not actually processed by find? Because in my experience they aren't, and we don't want them to be either as it would introduce a sort of infinite loop. This is also the case with mv replaced by cp, by the way.  The  (my emphasis)     If a file is removed from or added to the directory hierarchy being searched it is unspecified whether or not find includes that file in its search.   Since it's unspecified whether new files will be included, maybe a safer approach would be  find dir -type d -exec sh -c '     for n in "$1"/*.txt; do         test -f "$n" &amp;&amp; mv "$n" "${n%.txt}_hello.txt"     done' sh {} ';'   Here, we don't look for files but for directories, and the for loop of the internal sh script evaluates its range once before the first iteration, so we don't have the same potential issue.  The GNU find manual does not explicitly say anything about this and neither does the OpenBSD find manual.
16320
When I'm using  find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"  it finds all the types of file. But when I add -exec at the end:  find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt" -exec sh -c 'echo "$0"' {} \;  it seems it only prints .txt files. What am I doing wrong?  Note: using MINGW (Git Bash)
26823
I've hacked on a lot of shell scripts, and sometimes the simplest things baffle me. Today I ran across a script that made extensive use of the : (colon) bash builtin.  The  seems simple enough:   : (a colon)        : [arguments]         Do nothing beyond expanding arguments and performing redirections. The return status is zero.    However I have previously only seen this used in demonstrations of shell expansion. The use case in the script I ran across made extensive use of this structure:  if [ -f ${file} ]; then     grep some_string ${file} &gt;&gt; otherfile || :     grep other_string ${file} &gt;&gt; otherfile || : fi   There were actually hundreds of greps, but they are just more of the same. No input/output redirects are present other than  the simple structure above. No return values are checked later in the script.  I am reading this as a useless construct that says "or do nothing". What purpose could ending these greps with "or do nothing" serve? In what case would this construct cause a different outcome than simply leaving off the || : from all instances?