user6435535
user6435535

Reputation:

How to force command to execute in bash script

I want to use command substitution in a for loop in my bash script like this:

  for file in `ls`; do
    echo "$file"
    tar xzvf "$file"
  done

The problem is upon extracting each file and in the next iteration, ls would be executed again so the for loop iterate over new collection. I decided to capture ls output before starting the loop and use that in loop:

  files=`ls`
  for file in ${files}; do
    echo "$file"
    tar xzvf "$file"
  done

But it seems instead of running ls and store the result in $files, shell just replaces ${files} with ls and I'm at the same point as I was in first code example.

How can I force shell to run ls command in files=ls part of code?

Update

I'm on my Ubuntu 16.04 laptop:

$ uname -a
Linux laptop 4.4.0-131-generic #157-Ubuntu SMP Thu Jul 12 15:51:36 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

and GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

There is a folder in my home named test with two simple compressed files plus my script:

test
├── a.tar.gz
├── b.tar.gz
└── script.sh

script.sh content:

#!/usr/bin/env bash

  files=`ls`
  for file in ${files}; do
    echo "$file"
    tar xzvf "$file"
  done

And here is the output of bash -x script.sh from inside of test folder:

++ ls
+ files='a.tar.gz
b.tar.gz
script.sh'
+ for file in '${files}'
+ echo a.tar.gz
a.tar.gz
+ tar xzvf a.tar.gz
a
+ for file in '${files}'
+ echo b.tar.gz
b.tar.gz
+ tar xzvf b.tar.gz
b
+ for file in '${files}'
+ echo script.sh
script.sh
+ tar xzvf script.sh

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now

And finally bash script.sh (after deleting extracted files manually) output:

a.tar.gz
a
b.tar.gz
b
script.sh

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now

Thanks for your help and patience.

Upvotes: 2

Views: 4153

Answers (2)

user6435535
user6435535

Reputation:

It seems I was confused by tar command output because inside a.tar.gz there is a file named a and the same for b.tar.gz.

Changing the code as following solved the problem:

  files=`ls`
  for file in ${files}; do
    echo "$file"
    tar xzvf "$file" &> /dev/null
  done

Upvotes: 0

codeforester
codeforester

Reputation: 42999

Your script shouldn't be processing a file more than once and it wouldn't pick up the results of tar x in the same execution, unless it is rerun. However, there are a few issues there:

  • it would process any file, not just the tar.gz files
  • in case the script is rerun, it would pick up the result of previous extractions and it would also re-process all the tar.gz files previously expanded
  • it will fail in case any files have whitespaces in them (see ParsingLs)
  • there is no error checking to see if extraction was successful or not

So, it can be written in a better way to address the above issues:

for zipfile in *.tar.gz; do
  printf '%s\n' "Processing file '$zipfile'"
  tar xzvf "$zipfile" && mv "$zipfile" "$zipfile.done"
  if (($? == 0)); then
    printf '%s\n' "$zipfile: success"
  else
    printf '%s\n' "$zipfile: failure"
  fi
done

Upvotes: 4

Related Questions