Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute a command with a Bash variable in it and store the result

Tags:

bash

shell

unix

I don't know how to execute a command with a variable and get the result of this. I have many .h and .c files and I need convert each from ISO-8859 to UTF-8.

So I make:

ls | grep "\.[ch]" | xargs myscript.sh

And in my script, the filename is in variable $1. Now I need to perform

iconv -f ISO-8859 -t UTF-8 $1

and store result of this, because iconv prints to stdout.

result=`iconv -f ISO-8859 -t UTF-8 $1`

echo $result

This seems to be not working, because it gives me some mismatch instead of converted $1.

like image 627
designerrr Avatar asked Nov 29 '11 22:11

designerrr


People also ask

How do you store results of command in a variable?

To store the output of a command in a variable, you can use the shell command substitution feature in the forms below: variable_name=$(command) variable_name=$(command [option ...] arg1 arg2 ...) OR variable_name='command' variable_name='command [option ...]

How does bash execute a command?

Executing programs from a script. When the program being executed is a shell script, bash will create a new bash process using a fork. This subshell reads the lines from the shell script one line at a time. Commands on each line are read, interpreted and executed as if they would have come directly from the keyboard.

How do you use variables in bash commands?

Using variable from command line or terminal You don't have to use any special character before the variable name at the time of setting value in BASH like other programming languages. But you have to use '$' symbol before the variable name when you want to read data from the variable.

How do you record the output of a command in a bash script?

To get get result of command you need to use command substitution (bash feature). Command substitution provides executing a bash command/commands and store its output to variable. You can use special backticks (``). Everything what you write between backticks is executed by the shell before main command is executed.


3 Answers

If you need to do some kind of transformation on the data first, you can "capture" output with the following syntax:

result="$(iconv -f ISO-8859 -t UTF-8 $1)"

There is a gotcha here as well: if you are going to be storing large amounts of data with potential whitespace or other meddlesome characters in it, be sure to always quote the variable ("$result" instead of $result) to ensure it gets treated as a single string.

like image 96
Michael Avatar answered Oct 19 '22 09:10

Michael


I'd do as such:

while read filename; 
do
    mv "$filename" "$filename.bck" && \
        iconv -f ISO-8859 -t UTF-8 "$filename.bck" > "$filename"
done < find -iname '*.[hc]'

This creates backups on the fly and also handles files with whitespace (not newline characters).

like image 40
sehe Avatar answered Oct 19 '22 10:10

sehe


Here is a solution that even handles newlines:

find -name '*.[ch]' \
    -exec mv '{}' '{}.backup' \; \
    -exec iconv -f ISO-8859 -t UTF-8 '{}.backup' -o '{}' \;

Generally, never parse filenames if you are going to use the results. The only sane ways I know of are

  1. Use shell globs, e.g. for file in ./*.[ch] ; do echo "$file" ; done. Only works for one directory.
  2. Use find in combination with -exec
  3. Use 'find' in combination with -print0 (which prints the filenames as \0-separated strings) and use the output to build commandlines with xargs -0 and probably a helper script. This is quite cumbersome, though.

Also, make sure that relative filenames you use are prefixed with ./. Calling mv -from -to isn't safe, but mv ./-from ./-to is, and does what you want. E.g. when globbing, go with ./*.c rather than *.c.

like image 25
Jo So Avatar answered Oct 19 '22 09:10

Jo So