When I copy multiple paragraphs of data like
line 1
line 2
line 3
to my clipboard on Mac I can access its elements via AppleScript through
on run {input, parameters}
set theClip to input as text
set value of variable "Empfänger" of front workflow to paragraph 1 of theClip
set value of variable "Betreff" of front workflow to paragraph 2 of theClip
set value of variable "Textkörper" of front workflow to paragraph 3 of theClip
end run
and write it to Automator variables. Can I do the same thing in Shell-Script? When I run
for f in "$#"
do
echo "$f"
done
it seems like everything is stored in $1.
Actually, I wouldn't mind to use paragraphs as separator but a configurable sign like {NEXT} or something similar.
Thank you in advance!
Your example seems to be happy to treat a line as a paragraph. So, I'll do the same. So, if you copy your three lines of sample data into your clipboard by selecting them below and pressing ⌘C:
line1
line2
line3
and you want to separate them into shell variables, as you say:
para1=$(pbpaste | sed -ne '1p')
and check:
echo "$para1"
line 1
Likewise:
para2=$(pbpaste | sed -ne '2p')
para3=$(pbpaste | sed -ne '3p')
Or, if you mean you want the lines in an array:
paras=( $(pbpaste) )
echo ${paras[0]}
line1
echo ${paras[1]}
line2
Or, if you want loop over the elements:
for p in "${paras[#]}" ; do echo $p; done
What is the easiest way to append text to a file in Linux?
I had a look at this question, but the accepted answer uses an additional program (sed) I'm sure there should be an easier way with echo or similar.
How about:
echo "hello" >> <filename>
Using the >> operator will append data at the end of the file, while using the > will overwrite the contents of the file if already existing.
You could also use printf in the same way:
printf "hello" >> <filename>
Note that it can be dangerous to use the above. For instance if you already have a file and you need to append data to the end of the file and you forget to add the last > all data in the file will be destroyed. You can change this behavior by setting the noclobber variable in your .bashrc:
set -o noclobber
Now when you try to do echo "hello" > file.txt you will get a warning saying cannot overwrite existing file.
To force writing to the file you must now use the special syntax:
echo "hello" >| <filename>
You should also know that by default echo adds a trailing new-line character which can be suppressed by using the -n flag:
echo -n "hello" >> <filename>
References
echo(1) - Linux man page
noclobber variable
I/O Redirection
cat >> filename
This is text, perhaps pasted in from some other source.
Or else entered at the keyboard, doesn't matter.
^D
Essentially, you can dump any text you want into the file. CTRL-D sends an end-of-file signal, which terminates input and returns you to the shell.
Other possible way is:
echo "text" | tee -a filename >/dev/null
The -a will append at the end of the file.
If needing sudo, use:
echo "text" | sudo tee -a filename >/dev/null
Follow up to accepted answer.
You need something other than CTRL-D to designate the end if using this in a script. Try this instead:
cat << EOF >> filename
This is text entered via the keyboard or via a script.
EOF
This will append text to the stated file (not including "EOF").
It utilizes a here document (or heredoc).
However if you need sudo to append to the stated file, you will run into trouble utilizing a heredoc due to I/O redirection if you're typing directly on the command line.
This variation will work when you are typing directly on the command line:
sudo sh -c 'cat << EOF >> filename
This is text entered via the keyboard.
EOF'
Or you can use tee instead to avoid the command line sudo issue seen when using the heredoc with cat:
tee -a filename << EOF
This is text entered via the keyboard or via a script.
EOF
How can I write data to a text file automatically by shell scripting in Linux?
I was able to open the file. However, I don't know how to write data to it.
The short answer:
echo "some data for the file" >> fileName
However, echo doesn't deal with end of line characters (EOFs) in an ideal way. So, if you're going to append more than one line, do it with printf:
printf "some data for the file\nAnd a new line" >> fileName
The >> and > operators are very useful for redirecting output of commands, they work with multiple other bash commands.
#!/bin/sh
FILE="/path/to/file"
/bin/cat <<EOM >$FILE
text1
text2 # This comment will be inside of the file.
The keyword EOM can be any text, but it must start the line and be alone.
EOM # This will be also inside of the file, see the space in front of EOM.
EOM # No comments and spaces around here, or it will not work.
text4
EOM
You can redirect the output of a command to a file:
$ cat file > copy_file
or append to it
$ cat file >> copy_file
If you want to write directly the command is echo 'text'
$ echo 'Hello World' > file
#!/bin/bash
cat > FILE.txt <<EOF
info code info
info code info
info code info
EOF
I know this is a damn old question, but as the OP is about scripting, and for the fact that google brought me here, opening file descriptors for reading and writing at the same time should also be mentioned.
#!/bin/bash
# Open file descriptor (fd) 3 for read/write on a text file.
exec 3<> poem.txt
# Let's print some text to fd 3
echo "Roses are red" >&3
echo "Violets are blue" >&3
echo "Poems are cute" >&3
echo "And so are you" >&3
# Close fd 3
exec 3>&-
Then cat the file on terminal
$ cat poem.txt
Roses are red
Violets are blue
Poems are cute
And so are you
This example causes file poem.txt to be open for reading and writing on file descriptor 3. It also shows that *nix boxes know more fd's then just stdin, stdout and stderr (fd 0,1,2). It actually holds a lot. Usually the max number of file descriptors the kernel can allocate can be found in /proc/sys/file-max or /proc/sys/fs/file-max but using any fd above 9 is dangerous as it could conflict with fd's used by the shell internally. So don't bother and only use fd's 0-9. If you need more the 9 file descriptors in a bash script you should use a different language anyways :)
Anyhow, fd's can be used in a lot of interesting ways.
I like this answer:
cat > FILE.txt <<EOF
info code info
...
EOF
but would suggest cat >> FILE.txt << EOF if you want just add something to the end of the file without wiping out what is already exists
Like this:
cat >> FILE.txt <<EOF
info code info
...
EOF
Moving my comment as an answer, as requested by #lycono
If you need to do this with root privileges, do it this way:
sudo sh -c 'echo "some data for the file" >> fileName'
For environments where here documents are unavailable (Makefile, Dockerfile, etc) you can often use printf for a reasonably legible and efficient solution.
printf '%s\n' '#!/bin/sh' '# Second line' \
'# Third line' \
'# Conveniently mix single and double quotes, too' \
"# Generated $(date)" \
'# ^ the date command executes when the file is generated' \
'for file in *; do' \
' echo "Found $file"' \
'done' >outputfile
I thought there were a few perfectly fine answers, but no concise summary of all possibilities; thus:
The core principal behind most answers here is redirection. Two are important redirection operators for writing to files:
Redirecting Output:
echo 'text to completely overwrite contents of myfile' > myfile
Appending Redirected Output
echo 'text to add to end of myfile' >> myfile
Here Documents
Others mentioned, rather than from a fixed input source like echo 'text', you could also interactively write to files via a "Here Document", which are also detailed in the link to the bash manual above. Those answers, e.g.
cat > FILE.txt <<EOF` or `cat >> FILE.txt <<EOF
make use of the same redirection operators, but add another layer via "Here Documents". In the above syntax, you write to the FILE.txt via the output of cat. The writing only takes place after the interactive input is given some specific string, in this case 'EOF', but this could be any string, e.g.:
cat > FILE.txt <<'StopEverything'` or `cat >> FILE.txt <<'StopEverything'
would work just as well. Here Documents also look for various delimiters and other interesting parsing characters, so have a look at the docs for further info on that.
Here Strings
A bit convoluted, and more of an exercise in understanding both redirection and Here Documents syntax, but you could combine Here Document style syntax with standard redirect operators to become a Here String:
Redirecting Output of cat Input
cat > myfile <<<'text to completely overwrite contents of myfile'
Appending Redirected Output of cat Input
cat >> myfile <<<'text to completely overwrite contents of myfile'
This approach works and is the best
cat > (filename) <<EOF
Text1...
Text2...
EOF
Basically the text will search for keyword "EOF" till it terminates writing/appending the file
If you are using variables, you can use
first_var="Hello"
second_var="How are you"
If you want to concat both string and write it to file, then use below
echo "${first_var} - ${second_var}" > ./file_name.txt
Your file_name.txt content will be "Hello - How are you"
Can also use here document and vi, the below script generates a FILE.txt with 3 lines and variable interpolation
VAR=Test
vi FILE.txt <<EOFXX
i
#This is my var in text file
var = $VAR
#Thats end of text file
^[
ZZ
EOFXX
Then file will have 3 lines as below. "i" is to start vi insert mode and similarly to close the file with Esc and ZZ.
#This is my var in text file
var = Test
#Thats end of text file
I'm using Mach Desktop to echo a script's results into a Desklet, so it has to be in this format:
echo 'tell application "iTunes" to return album of current track' | osascript
I have a single line in which to enter data, so the script needs to be one long string.
It may be that the entire thing must be contained within one set of single quotes after echo, as follows:
echo '[entire script]' | osascript
How do I convert the AppleScript below to one line?
set some_file to "Macintosh HD:Users:Zade:Library:Application Support:Notational Data:Words.txt" as alias
set the_text to read some_file as string
set the text item delimiters of AppleScript to ", "
set the_lines to (every text item of the_text)
return some item of the_lines
Here is what I'm trying:
echo 'set some_file to "Macintosh HD:Users:Zade:Library:Application Support:Notational Data:Words.txt" as alias -e set the_text to read some_file as string -e set the text item delimiters of AppleScript to ", " -e set the_lines to (every text item of the_text) -e return some item of the_lines' | osascript
And that gives this error:
107:112: syntax error: A "set" can't go after this identifier. (-2740)
I suppose you could try out this script. I'm confused as to what you're actually trying to accomplish, though, so I apologize if this script is unsatisfactory.
echo 'set some_file to "~/Library/Application Support/Notational Data/Words.txt" as POSIX file as alias' -e 'set the_text to read some_file' -e 'set the text item delimeters of AppleScript to ","' -e 'set the lines to (every text item of the_text)' -e 'return the lines' | osascript
EDIT: #Zade That would be because Words.txt doesn't exist. Aliases only refer to existing files. Therefore, you must choose a file that exists. Here is an easy way to see what the correct syntax is for file references:
set some_file to (choose file)
You will notice that the file path is delimited by colons ( : ) rather than slashes. Having said this, choose a file that exists, and run your script with that file.
I'm writing a shell script that asks for a value and depending on the valued entered returns a value. Imagine that it's called "reve" and contains something like
read fname
rev << EOF
$fname
EOF
Then if I have a file that is called "file.txt" and I do
vi `./reve`
Then waits for user input. If I type "txt.elif" vi opens "file.txt". Correct until now. But the problem is when the script is something like the following
echo "Enter inverted file name"
read fname
rev << EOF
$fname
EOF
Then it tries to open a file called "Enter inverted file name".
Is it possible to ask for the value with the text and after that use the returned value only?
Thanks in advance.
If you really need it to be interactive, then you could print the message on stderr instead.
echo "Enter inverted file name" > /dev/stderr
read fname
rev << EOF
$fname
EOF
Unless you're using a really old shell, read should have a -p option to supply a prompt. It automatically sends the prompt to stderr instead of stdout, and skips the linefeed (so the response is on the same line as the prompt):
read -p "Enter inverted file name: " fname
rev << EOF
$fname
EOF
Force writing to, and reading from, the terminal using /dev/tty.
In your example this will be:
echo -e "Enter inverted file name: \c" > /dev/tty
read fname < /dev/tty
rev << EOF
$fname
EOF
I used echo -e ... \c so no newline is printed and your input is entered on the same line.